Ordenar y buscar en listas en Java

Ordenar en Java es una línea, hasta que aparecen los acentos y las mayúsculas. Esta página va de eso, de ordenar por varios criterios y de cuándo binarySearch miente.

Lo inmediato

var nums = new ArrayList<>(List.of(7, 2, 9, 4, 2));
Collections.sort(nums);                 // o nums.sort(null)
nums.sort(Comparator.reverseOrder());
salida[2, 2, 4, 7, 9]
  al revés: [9, 7, 4, 2, 2]

Ojo con una cosa: sort modifica la lista, y List.of(...) devuelve una lista inmutable. Por eso el new ArrayList<>(...) alrededor; sin él salta UnsupportedOperationException.

Y ahora, en español

var noms = new ArrayList<>(List.of("Marta", "ana", "Luis", "ángel"));
Collections.sort(noms);
noms.sort(String.CASE_INSENSITIVE_ORDER);
noms.sort(Collator.getInstance(Locale.of("es","ES")));
salidapor omisión:    [Luis, Marta, ana, ángel]
  sin mayúsculas: [ana, Luis, Marta, ángel]
  con Collator:   [ana, ángel, Luis, Marta]
Las tres líneas dan resultados distintos y solo la última está bien. El orden por omisión compara el valor numérico de cada carácter: las mayúsculas van antes que las minúsculas, y la «á» va muy por detrás de la «z». CASE_INSENSITIVE_ORDER arregla lo primero pero deja «ángel» al final. Para ordenar nombres como los ordenaría una persona hay que usar Collator con su idioma.

Por un campo, y por varios

ps.sort(Comparator.comparingDouble(Producto::precio));

ps.sort(Comparator.comparingInt(Producto::uds).reversed()
                  .thenComparing(Producto::nombre));
salidaprecio: [bufanda, gorra, neceser, mochila]
  uds desc, luego nombre: [gorra(7), mochila(7), neceser(3), bufanda(2)]

El segundo encadena: primero por unidades de mayor a menor, y a igualdad —gorra y mochila tienen 7— por nombre. Fíjate en el orden de las llamadas: reversed() invierte lo acumulado hasta ese punto, así que ponerlo al final habría invertido también el desempate.

Para números, usa comparingInt, comparingLong o comparingDouble en lugar de comparing: evitan empaquetar cada valor en un objeto.

Buscar

ord.contains(7);
ord.indexOf(4);
Collections.binarySearch(ord, 7);
Collections.binarySearch(ord, 5);
salidacontains(7)        true
  indexOf(4)         2
  binarySearch(7)    3
  binarySearch(5)    -4   -> insertar en 3
  max / min          9 / 2
  en desorden (mal)  2

contains e indexOf recorren la lista entera y valen siempre. binarySearch es mucho más rápida pero exige la lista ordenada, y cuando no encuentra el valor devuelve un negativo: -(posición de inserción) - 1. Por eso el −4 significa «no está, iría en la posición 3», que es justo lo que hace falta para insertar manteniendo el orden.

Y la última línea es la trampa: sobre una lista desordenada no da error, da una respuesta equivocada.

Quitar repetidos

new ArrayList<>(new LinkedHashSet<>(conRepes));   // conserva el orden de aparición
new ArrayList<>(new TreeSet<>(conRepes));         // además los ordena
salidaLinkedHashSet: [b, a, c]
  TreeSet      : [a, b, c]
Quieres… Usa
Ordenar números Collections.sort(lista)
Ordenar nombres en español Collator.getInstance(Locale.of("es","ES"))
Por un campo Comparator.comparingInt(T::campo)
Desempatar .thenComparing(...)
Al revés .reversed(), al final de lo que quieras invertir
Buscar rápido Collections.binarySearch, solo si está ordenada
Quitar repetidos pasar por un LinkedHashSet

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.