Java 44: Comparator Chaining — thenComparing, reversed & nullsFirst
easy⏱ 5 mincoursejava
comparing + thenComparing
Comparator.comparing(Person::lastName) construye un comparador a partir de un extractor de clave. Encadena .thenComparing(Person::firstName) para desempatar — los comparadores adicionales se consultan solo cuando el anterior devuelve 0. Expresa 'ordena por A, luego B, luego C' declarativamente, justo como un humano describe un orden.
people.sort(
Comparator.comparing(Person::lastName)
.thenComparing(Person::firstName)
.thenComparingInt(Person::age).reversed()
);
reversed() invierte toda la cadena
.reversed() invierte el comparador entero construido hasta ese punto — una trampa común. Para invertir solo una clave, invierte el comparador de esa clave antes de encadenar: .thenComparing(comparing(Person::age).reversed()), o usa comparing(Person::age, Comparator.reverseOrder()). Mezclar claves ascendentes y descendentes requiere este cuidado.
Comparators null-safe
Comparator.nullsFirst(naturalOrder()) trata null como el valor más pequeño; nullsLast como el más grande. Envuelve cualquier comparador para hacer null-tolerante la comparación entera. Combinado con comparing(extractor, nullsLast(naturalOrder())) puedes ordenar por una clave que puede ser null sin un NPE.
Ordena personas por 3 claves
Dado Person { last, first, age }, ordena por apellido ascendente, luego nombre ascendente, luego edad descendente, con clave de nombre null-safe. Usa un comparador encadenado (modela thenComparing probando cada clave en orden hasta que sea distinta de cero). Imprime el roster ordenado y confirma que dos 'Smith' desempatan por nombre.
Los Comparators deben ser consistentes con equals
Para TreeSet/TreeMap, un comparador que devuelve 0 para dos objetos no iguales los tratará como duplicados y descartará uno. Mantén compare(a,b)==0 ⇔ a.equals(b) para colecciones ordenadas; para un simple list.sort() está bien comparar por un subconjunto de campos.
Quiz: garantía de orden estable
¿Es estable Collections.sort / List.sort? Sí — es una variante de TimSort y preserva el orden relativo de elementos iguales. Por eso encadenar comparadores funciona: una primera pasada por nombre mantiene el orden relativo, y thenComparing solo refina los empates — aunque en la práctica encadenas en vez de confiar en varias pasadas.