Comparator.thenComparing în Java

thenComparing adaugă un criteriu secundar pentru elementele egale după primul; reversed() inversează un comparator.

Sintaxă
default Comparator<T> thenComparing(Comparator<? super T> other)
default <U extends Comparable<? super U>> Comparator<T> thenComparing(Function<? super T, ? extends U> cheie)
default Comparator<T> thenComparingInt(ToIntFunction<? super T> cheie)
default Comparator<T> reversed()

Ce face Comparator.thenComparing

c1.thenComparing(c2) returnează un comparator care folosește întâi c1, iar doar dacă c1 spune că elementele sunt egale (0), folosește c2. Așa sortezi „după clasă, apoi după nume, apoi după vârstă”. Există și variantele thenComparing(cheie), thenComparingInt, thenComparingDouble.

c.reversed() returnează comparatorul invers. Atenție: reversed() inversează tot lanțul construit până în acel punct. Pentru a inversa doar un criteriu, pune-l separat: comparing(A).thenComparing(comparing(B).reversed()) sau thenComparing(B, Comparator.reverseOrder()).

Parametri

Parametru Descriere
other Comparatorul secundar.
cheie Funcția care extrage proprietatea secundară.

Ce returnează

Un comparator nou, compus.

Exemple

Exemplul 1: Clasament: media descrescător, apoi numele

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    record Elev(String nume, double medie) {}

    public static void main(String[] args) {
        List<Elev> elevi = new ArrayList<>(List.of(
                new Elev("Radu", 9.50), new Elev("Ana", 9.80), new Elev("Elena", 9.50), new Elev("Bogdan", 8.90)));
        elevi.sort(Comparator.comparingDouble(Elev::medie).reversed().thenComparing(Elev::nume));
        int loc = 1;
        for (Elev e : elevi) {
            System.out.println(loc++ + ". " + e.nume() + " " + e.medie());
        }
    }
}

Rezultat

1. Ana 9.8
2. Elena 9.5
3. Radu 9.5
4. Bogdan 8.9

Exemplul 2: Unde pui reversed() contează

În primul caz, reversed() inversează ambele criterii; în al doilea, doar orașul crescător și vârsta descrescător.

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    record Persoana(String oras, int varsta) {}

    public static void main(String[] args) {
        List<Persoana> p = new ArrayList<>(List.of(
                new Persoana("Iași", 30), new Persoana("Arad", 25), new Persoana("Iași", 22), new Persoana("Arad", 41)));

        p.sort(Comparator.comparing(Persoana::oras).thenComparingInt(Persoana::varsta).reversed());
        System.out.println(p);

        p.sort(Comparator.comparing(Persoana::oras).thenComparing(Persoana::varsta, Comparator.reverseOrder()));
        System.out.println(p);
    }
}

Rezultat

[Persoana[oras=Iași, varsta=30], Persoana[oras=Iași, varsta=22], Persoana[oras=Arad, varsta=41], Persoana[oras=Arad, varsta=25]]
[Persoana[oras=Arad, varsta=41], Persoana[oras=Arad, varsta=25], Persoana[oras=Iași, varsta=30], Persoana[oras=Iași, varsta=22]]

Greșeli frecvente

  • Pui reversed() la final crezând că inversează doar ultimul criteriu. Inversează tot lanțul.
  • Sortezi de două ori (întâi după nume, apoi după medie) în loc de thenComparing. Merge doar pentru că sortarea e stabilă și doar în ordinea inversă a criteriilor; thenComparing e mai clar.

Comenzi înrudite

  • Comparator: Interfața care spune cum se ordonează două obiecte: compare(a, b) returnează un număr negativ, zero sau pozitiv.
  • Comparator.comparing: Construiește un comparator care ordonează obiectele după o proprietate: comparing(Elev::nume), comparingInt(Elev::varsta).
  • Comparator.naturalOrder: naturalOrder() compară obiectele după ordinea lor naturală (crescător); reverseOrder() după ordinea inversă (descrescător).
  • TreeSet: Mulțime care ține elementele mereu sortate (crescător sau după un Comparator) și oferă căutări de tip „cel mai mic”, „cel mai apropiat”.
  • List.sort: Sortează lista pe loc după comparatorul dat; cu null sortează în ordinea naturală (numere crescător, texte alfabetic).