L'interfaccia Map in Java

Concetti Chiave
  • L'interfaccia Map in Java rappresenta una collezione di coppie chiave/valore, dove le chiavi sono uniche e i valori possono essere duplicati.
  • Le mappe non implementano l'interfaccia Iterable, quindi non possono essere iterate direttamente con un ciclo for in stile for-each.
  • Le interfacce principali relative a Map includono Map.Entry, NavigableMap e SortedMap.
  • Le classi che implementano l'interfaccia Map includono HashMap, TreeMap, LinkedHashMap, IdentityHashMap e EnumMap.

Lavorare con le Map

Una mappa o Map è un oggetto che memorizza associazioni tra chiavi e valori, o coppie chiave/valore. Data una chiave, è possibile trovare il suo valore. Sia le chiavi che i valori sono oggetti. Le chiavi devono essere uniche, ma i valori possono essere duplicati. Alcune mappe possono accettare una chiave null e valori null, altre no.

C'è un punto chiave sulle mappe che è importante menzionare dall'inizio: non implementano l'interfaccia Iterable. Questo significa che non è possibile scorrere una mappa utilizzando un ciclo for in stile for-each. Inoltre, non è possibile ottenere un iteratore per una mappa. Tuttavia, come vedremo presto, è possibile ottenere una vista-collezione di una mappa, che permette l'uso sia del ciclo for che di un iteratore.

Le Interfacce relative a Map

Poiché le interfacce Map definiscono il carattere e la natura delle mappe, questa discussione sulle mappe inizia con esse.

Le seguenti interfacce supportano le mappe:

Interfaccia Descrizione
Map Mappa chiavi uniche a valori.
Map.Entry Descrive un elemento (una coppia chiave/valore) in una mappa. Questa è un'interfaccia annidata di Map.
NavigableMap Estende SortedMap per gestire il recupero di voci basato su ricerche di corrispondenza più vicina.
SortedMap Estende Map in modo che le chiavi siano mantenute in ordine crescente.
Tabella 1: Interfacce relative a Map

Ogni interfaccia viene esaminata di seguito.

L'Interfaccia Map

L'interfaccia Map mappa chiavi uniche a valori. Una chiave è un oggetto che usiamo per recuperare un valore in un momento successivo. Dato una chiave e un valore, possiamo memorizzare il valore in un oggetto Map. Dopo che il valore è memorizzato, possiamo recuperarlo utilizzando la sua chiave.

Map è generica ed è dichiarata come mostrato qui:

interface Map<K, V>

Qui, K specifica il tipo delle chiavi, e V specifica il tipo dei valori.

I metodi dichiarati da Map sono riassunti nella tabella seguente:

Metodo Descrizione
void clear() Rimuove tutte le coppie chiave/valore dalla mappa chiamante.
default V compute(K k, BiFunction<? super K, ? super V, ? extends V> func) Chiama func per costruire un nuovo valore. Se func restituisce un valore non null, la nuova coppia chiave/valore viene aggiunta alla mappa, qualsiasi accoppiamento preesistente viene rimosso, e il nuovo valore viene restituito. Se func restituisce null, qualsiasi accoppiamento preesistente viene rimosso, e null viene restituito.
default V computeIfAbsent(K k, Function<? super K, ? extends V> func) Restituisce il valore associato alla chiave k. Altrimenti, il valore viene costruito attraverso una chiamata a func e l'accoppiamento viene inserito nella mappa e il valore costruito viene restituito. Se nessun valore può essere costruito, null viene restituito.
default V computeIfPresent(K k, BiFunction<? super K, ? super V, ? extends V> func) Se k è nella mappa, un nuovo valore viene costruito attraverso una chiamata a func e il nuovo valore sostituisce il vecchio valore nella mappa. In questo caso, il nuovo valore viene restituito. Se il valore restituito da func è null, la chiave e il valore esistenti vengono rimossi dalla mappa e null viene restituito.
boolean containsKey(Object k) Restituisce true se la mappa chiamante contiene k come chiave. Altrimenti, restituisce false.
boolean containsValue(Object v) Restituisce true se la mappa contiene v come valore. Altrimenti, restituisce false.
static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> from) Restituisce una mappa che contiene le stesse coppie chiave/valore di quella specificata da from. La mappa restituita è non modificabile e basata sui valori. Chiavi o valori null non sono consentiti.
static <K, V> Map.Entry<K, V> entry(K k, V v) Restituisce una voce di mappa non modificabile basata sui valori composta dalla chiave e dal valore specificati. Una chiave o un valore null non è consentito.
Set<Map.Entry<K, V>> entrySet() Restituisce un Set che contiene le voci nella mappa. Il set contiene oggetti di tipo Map.Entry. Quindi, questo metodo fornisce una vista-set della mappa chiamante.
boolean equals(Object obj) Restituisce true se obj è una Map e contiene le stesse voci. Altrimenti, restituisce false.
default void forEach(BiConsumer<? super K, ? super V> action) Esegue action su ogni elemento nella mappa chiamante. Verrà lanciata una ConcurrentModificationException se un elemento viene rimosso durante il processo.
V get(Object k) Restituisce il valore associato alla chiave k. Restituisce null se la chiave non viene trovata.
default V getOrDefault(Object k, V defVal) Restituisce il valore associato a k se è nella mappa. Altrimenti, defVal viene restituito.
int hashCode() Restituisce il codice hash per la mappa chiamante.
boolean isEmpty() Restituisce true se la mappa chiamante è vuota. Altrimenti, restituisce false.
Set<K> keySet() Restituisce un Set che contiene le chiavi nella mappa chiamante. Questo metodo fornisce una vista-set delle chiavi nella mappa chiamante.
default V merge(K k, V v, BiFunction<? super V, ? super V, ? extends V> func) Se k non è nella mappa, l'accoppiamento k,v viene aggiunto alla mappa. In questo caso, v viene restituito. Altrimenti, func restituisce un nuovo valore basato sul vecchio valore, la chiave viene aggiornata per utilizzare questo valore, e merge() restituisce questo valore. Se il valore restituito da func è null, la chiave e il valore esistenti vengono rimossi dalla mappa e null viene restituito.
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, ...) Crea una mappa non modificabile basata sui valori contenente le voci specificate in lista-parametri. Chiavi o valori null non sono consentiti. Vengono fornite molte versioni sovraccaricate. Vedere la discussione nel testo per i dettagli.
static <K, V> Map<K, V> ofEntries(Map.Entry<? extends K, ? extends V>... voci) Restituisce una mappa non modificabile basata sui valori che contiene le mappature chiave/valore descritte dalle voci passate in voci. Chiavi o valori null non sono consentiti.
V put(K k, V v) Inserisce una voce nella mappa chiamante, sovrascrivendo qualsiasi valore precedente associato alla chiave. La chiave e il valore sono k e v, rispettivamente. Restituisce null se la chiave non esisteva già. Altrimenti, il valore precedente collegato alla chiave viene restituito.
void putAll(Map<? extends K, ? extends V> m) Inserisce tutte le voci da m in questa mappa.
default V putIfAbsent(K k, V v) Inserisce la coppia chiave/valore nella mappa chiamante se questo accoppiamento non è già presente o se il valore esistente è null. Restituisce il vecchio valore. Il valorenullviene restituito quando non esiste una mappatura precedente, o il valore è null.
V remove(Object k) Rimuove la voce la cui chiave è uguale a k.
default boolean remove(Object k, Object v) Se la coppia chiave/valore specificata da k e v è nella mappa chiamante, viene rimossa e true viene restituito. Altrimenti, false viene restituito.
default boolean replace(K k, V oldV, V newV) Se la coppia chiave/valore specificata da k e oldV è nella mappa chiamante, il valore viene sostituito da newV e true viene restituito. Altrimenti false viene restituito.
default V replace(K k, V v) Se la chiave specificata da k è nella mappa chiamante, il suo valore viene impostato a v e il valore precedente viene restituito. Altrimenti,nullviene restituito.
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> func) Esegue func su ogni elemento della mappa chiamante, sostituendo l'elemento con il risultato restituito da func. Verrà lanciata una ConcurrentModificationException se un elemento viene rimosso durante il processo.
int size() Restituisce il numero di coppie chiave/valore nella mappa.
Collection<V> values() Restituisce una collezione contenente i valori nella mappa. Questo metodo fornisce una vista-collezione dei valori nella mappa.
Tabella 2: I Metodi Dichiarati da Map

Diversi metodi lanciano una ClassCastException quando un oggetto è incompatibile con gli elementi in una mappa. Viene lanciata una NullPointerException se viene fatto un tentativo di utilizzare un oggetto null e null non è consentito nella mappa. Viene lanciata una UnsupportedOperationException quando viene fatto un tentativo di modificare una mappa non modificabile. Viene lanciata una IllegalArgumentException se viene utilizzato un argomento non valido.

Le mappe ruotano attorno a due operazioni di base: get() e put(). Per inserire un valore in una mappa, utilizziamo put(), specificando la chiave e il valore. Per ottenere un valore, chiamiamo get(), passando la chiave come argomento. Il valore viene restituito.

Come menzionato in precedenza, sebbene faccia parte del Collections Framework, le mappe non sono, esse stesse, collezioni perché non implementano l'interfaccia Collection. Tuttavia, possiamo ottenere una vista-collezione di una mappa. Per fare questo, possiamo utilizzare il metodo entrySet(). Restituisce un Set che contiene gli elementi nella mappa. Per ottenere una vista-collezione delle chiavi, utilizziamo keySet(). Per ottenere una vista-collezione dei valori, utilizziamo values(). Per tutte e tre le viste-collezione, la collezione è supportata dalla mappa. Modificare una influisce sull'altra. Le viste-collezione sono il mezzo attraverso il quale le mappe sono integrate nel più ampio Collections Framework.

A partire da JDK 9, Map include il metodo factory of(), che ha un numero di overload. Ogni versione restituisce una mappa non modificabile, basata su valore che è composta dagli argomenti che le vengono passati. Lo scopo principale di of() è fornire un modo conveniente ed efficiente per creare una piccola Map. Ci sono 11 overload di of(). Uno non prende argomenti e crea una mappa vuota. È mostrato qui:

static <K, V> Map<K, V> of()

Dieci overload prendono da 1 a 10 argomenti e creano una lista che contiene gli elementi specificati. Sono mostrati qui:

static <K, V> Map<K, V> of(K k1, V v1)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3)
...
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)

Per tutte le versioni, chiavi e/o valori null non sono consentiti. In tutti i casi, l'implementazione di Map non è specificata.

L'Interfaccia SortedMap

L'interfaccia SortedMap estende Map. Garantisce che le voci siano mantenute in ordine crescente basato sulle chiavi. SortedMap è generica ed è dichiarata come mostrato qui:

interface SortedMap<K, V>

Qui, K specifica il tipo delle chiavi, e V specifica il tipo dei valori.

I metodi aggiunti da SortedMap sono riassunti nella tabella seguente:

Metodo Descrizione
Comparator<? super K> comparator() Restituisce il comparatore della mappa ordinata invocante. Se l'ordinamento naturale è usato per la mappa invocante, viene restituito null.
K firstKey() Restituisce la prima chiave nella mappa invocante.
SortedMap<K, V> headMap(K fine) Restituisce una mappa ordinata per quelle voci della mappa con chiavi che sono minori di fine.
K lastKey() Restituisce l'ultima chiave nella mappa invocante.
SortedMap<K, V> subMap(K inizio, K fine) Restituisce una mappa contenente quelle voci con chiavi che sono maggiori o uguali a inizio e minori di fine.
SortedMap<K, V> tailMap(K inizio) Restituisce una mappa contenente quelle voci con chiavi che sono maggiori o uguali a inizio.
Tabella 3: I Metodi Dichiarati da SortedMap

Diversi metodi lanciano una NoSuchElementException quando non ci sono elementi nella mappa invocante. Una ClassCastException viene lanciata quando un oggetto è incompatibile con gli elementi in una mappa. Una NullPointerException viene lanciata se viene fatto un tentativo di usare un oggetto null quando null non è consentito nella mappa. Una IllegalArgumentException viene lanciata se viene usato un argomento non valido.

Le mappe ordinate permettono manipolazioni molto efficienti di sotto-mappa (in altre parole, sottoinsiemi di una mappa). Per ottenere una sotto-mappa, bisogna utilizzare headMap(), tailMap(), o subMap(). La sotto-mappa restituita da questi metodi è supportata dalla mappa invocante. Cambiare una cambia l'altra. Per ottenere la prima chiave nell'insieme, chiamare firstKey(). Per ottenere l'ultima chiave, usare lastKey().

L'Interfaccia NavigableMap

L'interfaccia NavigableMap estende SortedMap e dichiara il comportamento di una mappa che supporta il recupero di voci basato sulla corrispondenza più vicina a una chiave o chiavi date. NavigableMap è un'interfaccia generica che ha questa dichiarazione:

interface NavigableMap<K,V>

Qui, K specifica il tipo delle chiavi, e V specifica il tipo dei valori associati alle chiavi. Oltre ai metodi che eredita da SortedMap, NavigableMap aggiunge quelli riassunti nella tabella seguente:

Metodo Descrizione
Map.Entry<K, V> ceilingEntry(K obj) Cerca nella mappa la chiave più piccola k tale che k >= obj. Se tale chiave viene trovata, l'elemento corrispondente viene restituito. Altrimenti, viene restituito null.
K ceilingKey(K obj) Cerca nella mappa la chiave più piccola k tale che k >= obj. Se tale chiave viene trovata, viene restituita. Altrimenti, viene restituito null.
NavigableSet<K> descendingKeySet() Restituisce un NavigableSet che contiene le chiavi nella mappa invocante in ordine inverso. Quindi, restituisce una vista-set inversa delle chiavi. Il set risultante è sostenuto dalla mappa.
NavigableMap<K,V> descendingMap() Restituisce una NavigableMap che è l'inverso della mappa invocante. La mappa risultante è sostenuta dalla mappa invocante.
Map.Entry<K,V> firstEntry() Restituisce il primo elemento nella mappa. Questo è l'elemento con la chiave minore.
Map.Entry<K,V> floorEntry(K obj) Cerca nella mappa la chiave più grande k tale che k <= obj. Se tale chiave viene trovata, l'elemento corrispondente viene restituito. Altrimenti, viene restituito null.
K floorKey(K obj) Cerca nella mappa la chiave più grande k tale che k <= obj. Se tale chiave viene trovata, viene restituita. Altrimenti, viene restituito null.
NavigableMap<K,V> headMap(K upperBound, boolean incl) Restituisce una NavigableMap che include tutte le entrate dalla mappa invocante che hanno chiavi minori di upperBound. Se incl è true, allora un elemento uguale a upperBound è incluso. La mappa risultante è sostenuta dalla mappa invocante.
Map.Entry<K,V> higherEntry(K obj) Cerca nel set la chiave più grande k tale che k > obj. Se tale chiave viene trovata, l'elemento corrispondente viene restituito. Altrimenti, viene restituito null.
K higherKey(K obj) Cerca nel set la chiave più grande k tale che k > obj. Se tale chiave viene trovata, viene restituita. Altrimenti, viene restituito null.
Map.Entry<K,V> lastEntry() Restituisce l'ultimo elemento nella mappa. Questo è l'elemento con la chiave più grande.
Map.Entry<K,V> lowerEntry(K obj) Cerca nel set la chiave più grande k tale che k < obj. Se tale chiave viene trovata, l'elemento corrispondente viene restituito. Altrimenti, viene restituito null.
K lowerKey(K obj) Cerca nel set la chiave più grande k tale che k < obj. Se tale chiave viene trovata, viene restituita. Altrimenti, viene restituito null.
NavigableSet<K> navigableKeySet() Restituisce un NavigableSet che contiene le chiavi nella mappa invocante. Il set risultante è sostenuto dalla mappa invocante.
Map.Entry<K,V> pollFirstEntry() Restituisce il primo elemento, rimuovendo l'elemento nel processo. Poiché la mappa è ordinata, questo è l'elemento con il valore della chiave minore. null viene restituito se la mappa è vuota.
Map.Entry<K,V> pollLastEntry() Restituisce l'ultimo elemento, rimuovendo l'elemento nel processo. Poiché la mappa è ordinata, questo è l'elemento con il valore della chiave maggiore. null viene restituito se la mappa è vuota.
NavigableMap<K,V> subMap(K lowerBound, boolean lowIncl, K upperBound, boolean highIncl) Restituisce una NavigableMap che include tutti gli elementi dalla mappa invocante che hanno chiavi maggiori di lowerBound e minori di upperBound. Se lowIncl è true, allora un elemento uguale a lowerBound è incluso. Se highIncl è true, allora un elemento uguale a upperBound è incluso. La mappa risultante è sostenuta dalla mappa invocante.
NavigableMap<K,V> tailMap(K lowerBound, boolean incl) Restituisce una NavigableMap che include tutti gli elementi dalla mappa invocante che hanno chiavi maggiori di lowerBound. Se incl è true, allora un elemento uguale a lowerBound è incluso. La mappa risultante è sostenuta dalla mappa invocante.
Tabella 4: I Metodi Dichiarati da NavigableMap

Diversi metodi lanciano una ClassCastException quando un oggetto è incompatibile con le chiavi nella mappa. Una NullPointerException viene lanciata se si tenta di usare un oggetto null e le chiavi null non sono consentite nel set. Una IllegalArgumentException viene lanciata se viene usato un argomento non valido.

L'Interfaccia Map.Entry

L'interfaccia Map.Entry consente di lavorare con un'entrata della mappa. Ad esempio, ricordiamo che il metodo entrySet() dichiarato dall'interfaccia Map restituisce un Set contenente le entrate della mappa. Ognuno di questi elementi del set è un oggetto Map.Entry. Map.Entry è generica ed è dichiarata così:

interface Map.Entry<K, V>

Qui, K specifica il tipo di chiavi, e V specifica il tipo di valori. La tabella seguente riassume i metodi non statici dichiarati da Map.Entry:

Metodo Descrizione
boolean equals(Object obj) Restituisce true se obj è un Map.Entry la cui chiave e valore sono uguali a quelli dell'oggetto invocante.
K getKey() Restituisce la chiave per questo elemento della mappa.
V getValue() Restituisce il valore per questo elemento della mappa.
int hashCode() Restituisce il codice hash per questo elemento della mappa.
V setValue(V v) Imposta il valore per questo elemento della mappa a v. Una ClassCastException viene lanciata se v non è del tipo corretto per la mappa. Una IllegalArgumentException viene lanciata se c'è un problema con v. Una NullPointerException viene lanciata se v è null e la mappa non permette chiavi null. Una UnsupportedOperationException viene lanciata se la mappa non può essere cambiata.
Tabella 5: I Metodi Non Statici Dichiarati da Map.Entry

Map.Entry ha anche tre metodi statici:

  1. Il primo è comparingByKey(), che restituisce un Comparator<Map.Entry<K, V>> che confronta le entrate per chiave.
  2. Il secondo è comparingByValue(), che restituisce un Comparator<Map.Entry<K, V>> che confronta le entrate per valore.
  3. Il terzo è copyOf(), aggiunto da JDK 17. Restituisce un oggetto basato su valore non modificabile che è una copia dell'oggetto invocante, ma non fa parte di una mappa.

Le Classi Map

Diverse classi forniscono implementazioni delle interfacce Map. Le classi che possono essere utilizzate per le mappe sono riassunte qui:

Classe Descrizione
AbstractMap Implementa la maggior parte dell'interfaccia Map.
EnumMap Estende AbstractMap per l'uso con chiavi enum.
HashMap Estende AbstractMap per utilizzare una tabella hash.
TreeMap Estende AbstractMap per utilizzare un albero.
WeakHashMap Estende AbstractMap per utilizzare una tabella hash con chiavi deboli.
LinkedHashMap Estende HashMap per consentire iterazioni nell'ordine di inserimento.
IdentityHashMap Estende AbstractMap e utilizza l'uguaglianza di riferimento quando confronta documenti.
Tabella 6: Principali Classi che implementano Map

Notiamo che AbstractMap è una super-classe per tutte le implementazioni concrete di Map.

WeakHashMap implementa una mappa che utilizza "chiavi deboli", che consente a un elemento in una mappa di essere raccolto dal garbage collector quando la sua chiave non è altrimenti utilizzata. Questa classe non viene discussa ulteriormente qui. Le altre classi Map sono descritte nelle prossime lezioni.