Una Map è una struttura dati per memorizzare coppie chiave-valore. È simile ai dizionari di altri linguaggi di programmazione. L'interfaccia Map definisce le operazioni che puoi eseguire su una Map.
Java ha diverse implementazioni di Map. HashMap è una delle più usate.
// Make an instance
Map<String, Integer> fruitPrices = new HashMap<>();
Quando definisci una variabile Map, è consigliabile definirla come tipo Map invece che come il tipo specifico, come nell'esempio qui sopra.
Questa pratica rende facile cambiare in seguito l'implementazione di Map.
HashMap ha anche un costruttore di copia.
// Make a copy of a map
Map<String, Integer> copy = new HashMap<>(fruitPrices);
Aggiungi voci alla Map usando put.
fruitPrices.put("apple", 100);
fruitPrices.put("pear", 80);
// => { "apple" => 100, "pear" => 80 }
A ogni chiave può essere associato un solo valore.
Chiamare put con la stessa chiave aggiorna il valore di quella chiave.
fruitPrices.put("pear", 40);
// => { "apple" => 100, "pear" => 40 }
Usa get per ottenere il valore di una chiave.
fruitPrices.get("apple"); // => 100
Usa containsKey per verificare se la Map contiene una determinata chiave.
fruitPrices.containsKey("apple"); // => true
fruitPrices.containsKey("orange"); // => false
Rimuovi le voci con remove.
fruitPrices.put("plum", 90); // Add plum to map
fruitPrices.remove("plum"); // Removes plum from map
Il metodo size restituisce il numero di voci.
fruitPrices.size(); // Returns 2
Puoi usare i metodi keySet o values per ottenere rispettivamente le chiavi o i valori di una Map come Set o come Collection.
fruitPrices.keySet(); // Returns "apple" and "pear" in a set
fruitPrices.values(); // Returns 100 and 80, in a Collection
hashCode e equals
HashMap usa i metodi hashCode ed equals dell'oggetto per capire dove memorizzare i valori di una chiave e come recuperarli. Per questo motivo è importante che i loro valori restituiti non cambino tra la memorizzazione e il recupero. Altrimenti, la HashMap potrebbe non riuscire a trovare il valore.
Ad esempio, supponiamo di avere la seguente classe, che verrà usata come chiave di una Map:
public class Stock {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (Objects.equals(Stock.class, obj.getClass()) && obj instanceof Stock other) {
return Objects.equals(name, other.name);
}
return false;
}
}
hashCode ed equals dipendono dal campo name, che può essere modificato tramite setName.
Modificare l'hashCode può produrre risultati sorprendenti:
Stock stock = new Stock();
stock.setName("Beanies");
Map<Stock, Integer> stockCount = new HashMap<>();
stockCount.put(stock, 80);
stockCount.get(stock); // Returns 80
Stock other = new Stock();
other.setName("Beanies");
stockCount.get(other); // Returns 80 because "other" and "stock" are equal
stock.setName("Choccies");
stockCount.get(stock); // Returns null because hashCode value has changed
stockCount.get(other); // Also returns null because "other" and "stock" are not equal
stock.setName("Beanies");
stockCount.get(stock); // HashCode restored, so returns 80 again
stockCount.get(other); // Also returns 80 again because "other" and "stock" are back to equal
Un altro modo comune per creare delle Map è usare Map.of o Map.ofEntries.
// Using Map.of
Map<String, Integer> temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32);
// or using Map.ofEntries
Map<String, Integer> temperatures2 = Map.ofEntries(
Map.entry("Mon", 30),
Map.entry("Tue", 28),
Map.entry("Wed", 32)
);
A differenza di HashMap, popolano la Map in anticipo e diventano di sola lettura una volta create.
Map.copyOf crea una copia di sola lettura di una Map.
Map<String, Integer> readOnlyFruitPrices = Map.copyOf(fruitPrices);
Chiamare metodi come put, remove o clear genera una UnsupportedOperationException.