1. Introduzione
Nella vita reale ci imbattiamo spesso in situazioni in cui a ogni «chiave» unica bisogna associare un certo «valore». Una rubrica telefonica conserva il numero di telefono e il nome di una persona, un dizionario collega una parola alla sua traduzione, e in un registro dei voti ogni studente ha il proprio nome e il voto corrispondente.
In Java per questi compiti c’è l’interfaccia Map. È una collezione che memorizza coppie «chiave — valore» (key-value pair).
Proprietà principali di Map:
- Ogni chiave è unica (non sono ammessi duplicati).
- A una chiave può corrispondere un solo valore.
- I valori possono ripetersi.
Immaginiamo un’analogia. Se una lista (List) è come una fila in mensa (ognuno ha la propria posizione, si può accedere per indice), allora una mappa (Map) è come un armadietto con scomparti: ogni scomparto ha un numero (chiave) e dentro c’è qualcosa di proprio (valore).
Interfaccia Map: operazioni di base
L’interfaccia Map dichiara i metodi fondamentali per lavorare con coppie chiave-valore:
| Metodo | Descrizione |
|---|---|
|
Aggiungere/sostituire il valore per una chiave |
|
Ottenere il valore per una chiave |
|
Rimuovere la coppia per una chiave |
|
Verificare se esiste tale chiave |
|
Verificare se esiste tale valore |
|
Numero di coppie nella mappa |
|
Verificare se la mappa è vuota |
|
Rimuovere tutte le coppie |
I tipi K e V sono parametri generici: K (Key) è il tipo della chiave, V (Value) è il tipo del valore.
3. Classe HashMap: accesso rapido per chiave
Che cos’è HashMap?
HashMap è l’implementazione più diffusa dell’interfaccia Map. Fornisce accesso rapido ai valori per chiave.
Importante: HashMap non garantisce l’ordine di memorizzazione degli elementi! Se aggiungete le chiavi in un certo ordine, in iterazione potrebbero comparire in un altro.
Come creare una HashMap?
import java.util.HashMap;
import java.util.Map;
public class Example {
public static void main(String[] args) {
// Creiamo una mappa: chiave — String, valore — Integer
Map<String, Integer> ages = new HashMap<>();
// Aggiungiamo elementi
ages.put("Vasya", 25);
ages.put("Petya", 30);
ages.put("Masha", 22);
// Otteniamo un valore per chiave
int vasyaAge = ages.get("Vasya");
System.out.println("Età di Vasya: " + vasyaAge); // 25
// Verifichiamo la presenza della chiave
if (ages.containsKey("Masha")) {
System.out.println("Masha è nell'elenco!");
}
// Rimuoviamo un elemento
ages.remove("Petya");
// Iteriamo su tutte le coppie chiave-valore
for (String name : ages.keySet()) {
System.out.println(name + ": " + ages.get(name));
}
}
}
Output:
Età di Vasya: 25
Masha è nell'elenco!
Vasya: 25
Masha: 22
Caratteristiche di HashMap
La cosa principale da ricordare: le chiavi in HashMap sono sempre uniche. Se inserite un nuovo elemento con una chiave già esistente, il valore precedente verrà sostituito con quello nuovo.
I valori possono ripetersi: diverse chiavi possono riferirsi allo stesso valore.
E un altro punto importante — l’ordine degli elementi. HashMap non si preoccupa dell’ordine di inserimento. In output le voci possono risultare rimescolate — è un comportamento normale.
4. Classe TreeMap: ordinamento per chiave
A differenza di HashMap, la classe TreeMap memorizza gli elementi in ordine ordinato per chiave.
Quando usare TreeMap?
Quando è importante che gli elementi siano in ordine crescente (o decrescente) delle chiavi. Ad esempio, se volete stampare una rubrica in ordine alfabetico.
Esempio:
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
Map<String, String> phoneBook = new TreeMap<>();
phoneBook.put("Vasya", "+1-900-123-45-67");
phoneBook.put("Masha", "+1-900-555-55-55");
phoneBook.put("Petya", "+1-900-222-33-44");
for (String name : phoneBook.keySet()) {
System.out.println(name + ": " + phoneBook.get(name));
}
}
}
Output:
Masha: +1-900-555-55-55
Petya: +1-900-222-33-44
Vasya: +1-900-123-45-67
Da notare: le chiavi sono ordinate alfabeticamente.
5. Operazioni principali con Map
Aggiunta e sostituzione di elementi
Map<String, Integer> scores = new HashMap<>();
scores.put("Anna", 90);
scores.put("Ivan", 85);
scores.put("Anna", 95); // Sovrascriverà il valore per "Anna"
Ottenere un valore
Integer annaScore = scores.get("Anna"); // 95
Integer unknown = scores.get("Vasya"); // null, se tale chiave non esiste
Verifica della presenza di una chiave o di un valore
scores.containsKey("Ivan"); // true
scores.containsValue(85); // true
Rimozione di una coppia per chiave
scores.remove("Ivan");
Dimensione della mappa e pulizia
int size = scores.size();
scores.clear(); // Rimuove tutti gli elementi
5. Iterare sugli elementi di Map
Map non è una lista, non ci sono indici. Ma si può iterare:
Per chiavi:
for (String key : scores.keySet()) {
System.out.println("Chiave: " + key + ", Valore: " + scores.get(key));
}
Per valori:
for (Integer value : scores.values()) {
System.out.println("Valore: " + value);
}
Per coppie chiave-valore (il modo migliore):
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " => " + value);
}
Quando usare HashMap e quando — TreeMap?
HashMap è l’opzione «predefinita» universale. Se l’ordine delle chiavi non è importante e la priorità è la velocità delle operazioni, quasi sempre si sceglie questa.
TreeMap è utile quando serve un ordine. Mantiene automaticamente le chiavi ordinate e consente di trovare rapidamente la chiave minima/massima o di lavorare con intervalli.
In sintesi: nel 90 % dei casi usiamo HashMap. Quando i dati devono essere subito «in ordine», utilizziamo TreeMap.
6. Esempi di utilizzo di Map
Esempio 1: Rubrica telefonica
Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Katya", "+1-999-111-22-33");
phoneBook.put("Oleg", "+1-999-222-33-44");
phoneBook.put("Katya", "+1-999-555-66-77"); // Il vecchio numero di Katya verrà sostituito dal nuovo
for (Map.Entry<String, String> entry : phoneBook.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Output:
Oleg: +1-999-222-33-44
Katya: +1-999-555-66-77
Esempio 2: Conteggio delle parole
Supponiamo di avere un elenco di parole e di voler sapere quante volte compare ciascuna parola:
import java.util.*;
public class WordCount {
public static void main(String[] args) {
List<String> words = Arrays.asList("mela", "banana", "mela", "pera", "banana", "mela");
Map<String, Integer> counts = new HashMap<>();
for (String word : words) {
int oldCount = counts.getOrDefault(word, 0); // se la chiave non esiste — 0
counts.put(word, oldCount + 1);
}
System.out.println(counts); // {pera=1, mela=3, banana=2}
}
}
7. Errori tipici nell'uso di Map
Errore n. 1: confusione tra chiavi e valori. Spesso i principianti tentano di ottenere un valore per indice, come in una lista, o dimenticano che le chiavi devono essere uniche. In Map non ci sono indici — solo chiavi.
Errore n. 2: uso di chiavi e valori null. In HashMap è consentita una chiave null, ma in TreeMap — no (si avrà una NullPointerException). I valori possono essere null in entrambe le implementazioni, ma è raramente utile.
Errore n. 3: aspettarsi un ordine degli elementi in HashMap. HashMap non garantisce alcun ordine. Se serve un ordine — usate LinkedHashMap (mantiene l’ordine di inserimento) oppure TreeMap (ordina per chiave).
Errore n. 4: modificare la mappa durante l’iterazione. Se iterate su una Map e contemporaneamente aggiungete/rimuovete elementi — può verificarsi una ConcurrentModificationException. Per questi casi usate un iteratore con il metodo remove() o collezioni speciali.
Errore n. 5: confrontare chiavi e valori con == invece di equals. Map usa il metodo equals per confrontare le chiavi (e i valori). Se create le vostre classi da usare come chiavi, ricordate di sovrascrivere equals e hashCode.
GO TO FULL VERSION