Comparator în Java

Comparator și Optional Java 1.2 (metodele default și statice: Java 8)

Interfața care spune cum se ordonează două obiecte: compare(a, b) returnează un număr negativ, zero sau pozitiv.

Sintaxă
import java.util.Comparator;

@FunctionalInterface
public interface Comparator<T> {
    int compare(T a, T b);
}

Ce face Comparator

Un Comparator<T> este o regulă de ordonare. Metoda lui compare(a, b) returnează un număr negativ dacă a trebuie să vină înaintea lui b, zero dacă sunt „egale” pentru ordonare și pozitiv dacă a vine după b.

Îl dai metodelor care sortează sau caută extreme: lista.sort(c), Collections.sort(lista, c), Arrays.sort(a, c), new TreeSet<>(c), new PriorityQueue<>(c), Collections.max(colectie, c), stream.sorted(c).

Rareori scrii compare de mână. Metodele gata făcute construiesc comparatorul: Comparator.comparing(Elev::nume), comparingInt, naturalOrder, reverseOrder, apoi le combini cu thenComparing și reversed.

Parametri

Parametru Descriere
T Tipul obiectelor comparate.

Ce returnează

compare returnează un int: < 0, 0 sau > 0.

Exemple

Exemplul 1: Un comparator scris ca lambda

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

public class Main {
    public static void main(String[] args) {
        Comparator<String> dupaLungime = (a, b) -> Integer.compare(a.length(), b.length());
        List<String> orase = new ArrayList<>(List.of("Constanța", "Iași", "Brașov", "Arad"));
        orase.sort(dupaLungime);
        System.out.println(orase);
        System.out.println(dupaLungime.compare("Iași", "Brașov"));
        System.out.println(dupaLungime.compare("Iași", "Arad"));
    }
}

Rezultat

[Iași, Arad, Brașov, Constanța]
-1
0

Exemplul 2: Același comparator în mai multe locuri

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;

public class Main {
    record Produs(String nume, double pret) {}

    public static void main(String[] args) {
        Comparator<Produs> dupaPret = Comparator.comparingDouble(Produs::pret);
        List<Produs> produse = List.of(new Produs("cafea", 24.5), new Produs("ceai", 9.9), new Produs("lapte", 7.2));
        System.out.println("Cel mai scump: " + Collections.max(produse, dupaPret).nume());
        TreeSet<Produs> sortate = new TreeSet<>(dupaPret);
        sortate.addAll(produse);
        sortate.forEach(p -> System.out.println(p.nume() + " " + p.pret()));
    }
}

Rezultat

Cel mai scump: cafea
lapte 7.2
ceai 9.9
cafea 24.5

Greșeli frecvente

  • Scrii (a, b) -> a.varsta() - b.varsta(). Pentru numere mari scăderea poate depăși int și dă semnul greșit; folosește Integer.compare sau Comparator.comparingInt.
  • Comparatorul returnează 0 pentru obiecte diferite într-un TreeSet/TreeMap. Sunt considerate același element și unul dispare; adaugă criterii cu thenComparing.
  • Confunzi Comparator (regulă separată) cu Comparable (ordinea „naturală” scrisă în clasă prin compareTo).

Comenzi înrudite

  • Comparator.comparing: Construiește un comparator care ordonează obiectele după o proprietate: comparing(Elev::nume), comparingInt(Elev::varsta).
  • Comparator.thenComparing: thenComparing adaugă un criteriu secundar pentru elementele egale după primul; reversed() inversează un comparator.
  • Comparator.naturalOrder: naturalOrder() compară obiectele după ordinea lor naturală (crescător); reverseOrder() după ordinea inversă (descrescător).
  • List.sort: Sortează lista pe loc după comparatorul dat; cu null sortează în ordinea naturală (numere crescător, texte alfabetic).
  • Collections.sort: Sortează o listă pe loc: crescător după ordinea naturală sau după un Comparator dat. Echivalent cu lista.sort(…).
  • 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”.