Ordenación de Map por valores en Java: cómo no pisar los mismos rastrillos (y otros nuevos también)
\n\n«¡Necesito ordenar un HashMap por valores!» — esta pregunta en Stack Overflow acumula miles de visitas y decenas de respuestas. ¿Parece que podría ser más sencillo? Tomas un Map, lo ordenas por values()… y te duele la cabeza. Porque ordenar un Map por valores en Java es esa tarea donde los principiantes (e incluso desarrolladores experimentados) cometen los mismos errores una y otra vez.
En este artículo analizaremos los 5 errores más comunes al ordenar un HashMap por valores, mostraremos las soluciones correctas y daremos plantillas de código listas para usar. ¡Allá vamos!
\n\nError n.º 1: Intento ingenuo de ordenar el propio HashMap
\n\nEl error más común es pensar que se puede ordenar un HashMap «en el lugar». HashMap no garantiza el orden de los elementos — es su propiedad fundamental. No puedes simplemente llamar a sort() en un HashMap porque no tiene ese método.
Así es como NO se debe hacer:
\n\n// ❌ ERROR: No se puede ordenar un HashMap directamente\nMap<String, Integer> scores = new HashMap<>();\nscores.put("Alice", 95);\nscores.put("Bob", 80);\nscores.put("Charlie", 90);\n\n// ¡Este método no existe!\n// scores.sort(...); // Error de compilación\n\n¿Por qué no funciona? HashMap usa hashing para almacenar pares clave-valor. El orden está determinado por los códigos hash de las claves y puede cambiar al agregar nuevos elementos. Ordenar un Map por valores solo es posible creando una nueva estructura de datos, por ejemplo, LinkedHashMap.
Solución correcta: creamos un nuevo LinkedHashMap
\n\n// ✅ CORRECTO: ordenamos las entradas y las guardamos en un LinkedHashMap\nMap<String, Integer> sortedMap = scores.entrySet()\n .stream()\n .sorted(Map.Entry.comparingByValue())\n .collect(Collectors.toMap(\n Map.Entry::getKey,\n Map.Entry::getValue,\n (e1, e2) -> e1, // resolvemos conflictos (si las claves se duplican)\n LinkedHashMap::new // preservamos el orden de inserción\n ));\n\nSystem.out.println(sortedMap);\n// {Bob=80, Charlie=90, Alice=95} — ¡ordenado ascendentemente!\n\nError n.º 2: Olvidar LinkedHashMap al recopilar
\n\nIncluso los desarrolladores Java experimentados a veces escriben este código:
\n\n// ⚠️ CASI CORRECTO, pero hay un detalle\nMap<String, Integer> result = scores.entrySet()\n .stream()\n .sorted(Map.Entry.comparingByValue())\n .collect(Collectors.toMap(\n Map.Entry::getKey,\n Map.Entry::getValue\n )); // ¡Por defecto Collectors.toMap() crea un HashMap!\n\n¿Cuál es el truco? Collectors.toMap() sin especificar un proveedor (supplier) crea un HashMap. Y HashMap no garantiza el orden! Tu ordenación se habrá realizado, pero el resultado puede parecer desordenado. Este es uno de los errores más engañosos en Java al ordenar un Map.
Cómo corregirlo
\n\nSiempre especifica explícitamente LinkedHashMap::new como cuarto argumento:
// ✅ GARANTIZADAMENTE CORRECTO\nMap<String, Integer> result = scores.entrySet()\n .stream()\n .sorted(Map.Entry.comparingByValue())\n .collect(Collectors.toMap(\n Map.Entry::getKey,\n Map.Entry::getValue,\n (oldVal, newVal) -> oldVal,\n LinkedHashMap::new // ¡Punto clave!\n ));\n\nError n.º 3: Ordenar por valores cuando no son Comparable
\n\nSupongamos que tienes un Map<String, CustomObject>. Escribes:
// ❌ ERROR: CustomObject no implementa Comparable\nMap<String, CustomObject> map = new HashMap<>();\n// ...\nmap.entrySet().stream()\n .sorted(Map.Entry.comparingByValue()) // ¡Error de compilación!\n