Un Map almacena pares clave-valor
Un HashMap (de java.util) almacena asociaciones: cada clave se asigna a un valor, y buscas los valores por su clave en tiempo aproximadamente constante. Piensa en un diccionario: la palabra es la clave y la definición es el valor.
Los dos parámetros de tipo son <KeyType, ValueType>. Aquí las claves son String y los valores son Integer. Al igual que con ArrayList, normalmente declaras la variable con el tipo de la interfaz Map y construyes un HashMap.
put, get y sobrescritura
Dos cosas que conviene interiorizar:
- Una clave es única.
putcon una clave existente reemplaza su valor y devuelve el anterior. getsobre una clave inexistente devuelvenull, no un error. Hacer el auto-unboxing de esenulla unintlanza unaNullPointerException, una fuente habitual de errores.
getOrDefault evita la trampa del null
En lugar de comprobar null cada vez, pide un valor por defecto:
Esta es la forma más limpia de manejar búsquedas de elementos "tal vez presentes", y conduce directamente al patrón de HashMap más famoso.
Contar ocurrencias
Contar cuántas veces aparece cada elemento es la tarea de manual para un HashMap:
El patrón map.put(key, map.getOrDefault(key, 0) + 1) se lee como "toma el conteo actual (o cero), súmale uno y vuélvelo a guardar". Un equivalente más elegante es counts.merge(word, 1, Integer::sum).
Comprobar y eliminar
putIfAbsent(key, value) solo escribe cuando la clave no existe, útil para la inicialización perezosa.
Recorrer un HashMap
El bucle más común recorre entrySet(), dándote cada clave y valor juntos:
Si solo necesitas las claves o solo los valores:
También puedes usar forEach con una lambda: ages.forEach((name, age) -> System.out.println(name + ": " + age));.
El HashMap no conserva el orden
Un HashMap no garantiza ningún orden de iteración: es el que produce el hashing, y puede cambiar entre ejecuciones. Si necesitas un orden predecible:
LinkedHashMapconserva el orden de inserción.TreeMapmantiene las claves ordenadas por su orden natural (o por unComparatorque proporciones).
Las tres implementan la interfaz Map, así que cambiar de una a otra es modificar una sola línea en el constructor.
Las claves deben ser hashables
HashMap encuentra las entradas haciendo hash de la clave, por lo que el hashCode() y el equals() de una clave deben ser coherentes entre sí. Los tipos integrados como String e Integer ya lo hacen correctamente. Si usas tu propia clase como clave, sobrescribe tanto equals como hashCode; de lo contrario, dos objetos que sean "iguales" en significado terminarán en cubetas distintas y tus búsquedas fallarán de forma misteriosa.
Siguiente: HashSet
Un HashMap responde a "¿qué valor está almacenado bajo esta clave?". Cuando solo te importa si algo está presente o no (un conjunto de valores únicos, sin datos asociados), la herramienta es HashSet, que viene a continuación.
Preguntas frecuentes
¿Cómo se crea un HashMap en Java?
Declaralo con dos parámetros de tipo (el tipo de la clave y el tipo del valor) y llama al constructor: Map<String, Integer> ages = new HashMap<>();. Luego añade entradas con ages.put("Ada", 36); y léelas con ages.get("Ada");. Importa java.util.HashMap y java.util.Map.
¿Cómo se recorre un HashMap en Java?
Itera sobre map.entrySet() con un bucle for-each para obtener cada clave y valor a la vez: for (Map.Entry<String, Integer> e : map.entrySet()) { ... }, leyendo e.getKey() y e.getValue(). También puedes recorrer map.keySet() para obtener solo las claves o map.values() para obtener solo los valores. Ten en cuenta que un HashMap no conserva el orden de inserción.
¿Cuál es la diferencia entre get y getOrDefault?
get(key) devuelve el valor de una clave, o null si la clave no existe, lo que puede provocar una NullPointerException si usas el resultado directamente. getOrDefault(key, fallback) devuelve el valor si está presente y, en caso contrario, el valor por defecto que pases, así evitas la comprobación de null. Es especialmente útil para contar: counts.put(c, counts.getOrDefault(c, 0) + 1).