Ús de mapes
- Operacions bàsiques
- Recórrer un mapa
- Els mètodes que estalvien codi
- Les implementacions
- Mapes immutables
- Referències
Un Map<K, V> associa claus úniques a valors. És l’estructura per respondre “quin valor correspon a aquesta clau” sense haver de recórrer res:
Map<String, String> telefons = new HashMap<>();
telefons.put("Aina", "600111222");
telefons.put("Bernat", "600333444");
telefons.get("Aina"); // "600111222"
telefons.get("Carla"); // null: la clau no hi és
Una clau no es pot repetir. Si tornes a fer put() amb una clau que ja hi és, el valor antic queda substituït, i el mètode te’l retorna per si el necessites.
Operacions bàsiques
| Mètode | Què fa |
|---|---|
V put(K, V) | Desa la parella i retorna el valor anterior, o null |
V get(Object) | El valor de la clau, o null si no hi és |
boolean containsKey(Object) | Si la clau hi és |
V remove(Object) | Treu la parella i retorna el valor que hi havia |
int size(), boolean isEmpty(), void clear() | Mida i buidatge |
get() retorna null tant si la clau no hi és com si el valor desat és null. Si necessites distingir els dos casos, fes servir containsKey().
Recórrer un mapa
Un mapa dona tres vistes del seu contingut: keySet() amb les claus, values() amb els valors i entrySet() amb les parelles. Cada parella és un Map.Entry<K, V> amb getKey() i getValue().
for (Map.Entry<String, String> entrada : telefons.entrySet()) {
System.out.println(entrada.getKey() + ": " + entrada.getValue());
}
Si només necessites llegir, forEach() és més curt:
telefons.forEach((nom, telefon) -> System.out.println(nom + ": " + telefon));
Recorre sempre amb entrySet() i no amb keySet() seguit d’un get() per cada clau: la segona forma torna a buscar cada clau i no aporta res.
Els mètodes que estalvien codi
Aquestes són les operacions que separen el codi de qui coneix l’API del de qui no. Comptar quantes vegades apareix cada paraula, a mà:
if (comptador.containsKey(paraula)) {
comptador.put(paraula, comptador.get(paraula) + 1);
} else {
comptador.put(paraula, 1);
}
I amb merge(), que rep el valor inicial i què fer si la clau ja hi era:
comptador.merge(paraula, 1, Integer::sum);
Agrupar elements en llistes, amb computeIfAbsent(), que crea el valor només si falta:
Map<Character, List<String>> perInicial = new HashMap<>();
perInicial.computeIfAbsent(nom.charAt(0), inicial -> new ArrayList<>()).add(nom);
| Mètode | Quan |
|---|---|
getOrDefault(clau, valorPerDefecte) | Llegir amb un valor de recanvi, en lloc de null |
putIfAbsent(clau, valor) | Desar només si la clau encara no hi és |
computeIfAbsent(clau, funcio) | Crear el valor la primera vegada, típicament una llista o un conjunt |
merge(clau, inicial, funcio) | Acumular: comptadors, sumes, concatenacions |
compute(clau, funcio) | Recalcular a partir de la clau i el valor actual |
Les implementacions
Les tres implementacions es fan servir igual i només es diferencien en l’ordre de recorregut i en què demanen a les claus:
| Implementació | Ordre en recórrer | Requisit de la clau |
|---|---|---|
HashMap | Cap: pot canviar entre execucions | equals() i hashCode() ben implementats |
LinkedHashMap | El d’inserció | Els mateixos |
TreeMap | El de les claus, de menor a major | Han de ser comparables, o cal donar un Comparator al constructor |
HashMap és la tria per defecte. Passa a LinkedHashMap quan l’ordre de recorregut ha de ser previsible, per exemple si el resultat es mostra a l’usuari, i a TreeMap quan necessites recórrer per ordre de clau o buscar rangs.
Els requisits de la clau són els mateixos de què parla Comparació d’objectes, i el motiu és el mateix: HashMap col·loca les claus segons el seu hashCode(), i TreeMap les manté ordenades amb compareTo().
Mapes immutables
Map.of() crea un mapa petit i immutable en una línia, còmode per a taules de constants:
Map<String, Integer> dies = Map.of("gener", 31, "febrer", 28, "març", 31);
No admet claus ni valors null, l’ordre de recorregut no està garantit, i qualsevol intent de modificar-lo llança UnsupportedOperationException. Si el que vols és una còpia immutable d’un mapa existent, fes servir Map.copyOf(altre).