In Java, le mappe sono strutture dati che associano chiavi a valori, consentendo di memorizzare, accedere, aggiornare e rimuovere in modo efficiente coppie chiave-valore. A differenza delle collezioni, che memorizzano solo elementi, le mappe mantengono una relazione di associazione in cui ogni chiave è univoca e punta a un solo valore, anche se più chiavi possono essere associate allo stesso valore.

L’interfaccia Map fornisce meccanismi per ottenere valori a partire da chiavi univoche (non duplicate). Fornisce inoltre tre viste di collezione che consentono di manipolare il contenuto di una mappa in modi diversi: come insieme di chiavi, come collezione di valori oppure come insieme di associazioni tra chiavi e valori. La principale interfaccia derivata da Map è SortedMap, che rappresenta mappe ordinate, insieme alla sua sottointerfaccia NavigableMap. Map è ampiamente utilizzata dalle classi della libreria standard. Le principali classi che implementano l’interfaccia Map per le mappe non concorrenti sono HashMap, LinkedHashMap e TreeMap. Per le mappe concorrenti, le classi principali sono ConcurrentHashMap e ConcurrentSkipListMap.

Di seguito è riportata una parte della definizione dell’interfaccia Map, contenente solo i metodi principali:

public interface Map<K,V>{
    // Query Operations
    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);

    // Modification Operations
    V put(K key, V value);
    V remove(Object key);
    void putAll(Map<? extends K, ? extends V> m);
    void clear();

    // Views
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();

    // Definition of the Entry interface
    interface Entry<K, V> {
        // Body omitted
    }

    // (continues...)
}

L’esempio seguente mostra una mappa di automobili le cui chiavi sono le targhe e i cui valori sono i nomi dei relativi modelli. Con questa mappa possiamo, ad esempio, verificare se un determinato elemento esiste utilizzando la chiave come parametro del metodo containsKey. Inoltre, il metodo get restituisce il valore associato alla chiave passata come parametro, mentre il metodo remove rimuove l’elemento dalla mappa:

void main() {
    Map<String, String> cars = new HashMap<>();
    cars.put("ABCD2935", "Tesla Model S");
    cars.put("YJKF9353", "Toyota Corolla");
    cars.put("WFLO1304", "Honda CRV");

    var key = "ABCD2935";

    if (cars.containsKey(key)){
        IO.println("Vehicle data:");
        IO.println(cars.get(key));
        IO.println("Removing the vehicle...");
        cars.remove(key);
    } else
        IO.println("Vehicle not found!");
}
Vehicle data:
Tesla Model S
Removing the vehicle...

Oltre ai metodi descritti sopra, esistono anche diversi metodi default che implementano funzionalità aggiuntive.

L’interfaccia fornisce inoltre metodi per creare mappe immutabili a partire da valori forniti (i metodi of e ofEntries, insieme al metodo ausiliario entry) oppure da una mappa esistente (copyOf).

La Figura 1 mostra l’interfaccia Map e le sue principali sottointerfacce. Le sottointerfacce dirette di Map sono SequencedMap, Bindings e ConcurrentMap. Indirettamente, anche SortedMap, NavigableMap e ConcurrentNavigableMap sono interfacce derivate da Map (quest’ultima è inoltre una sottointerfaccia di ConcurrentMap).

Interfaccia Map e le sue sottointerfacce

Tra i discendenti più importanti di Map vi sono le interfacce SortedMap e NavigableMap.

L’interfaccia SortedMap è un’estensione dell’interfaccia SequencedMap che rappresenta mappe che mantengono le proprie chiavi in un ordine specifico, secondo l’ordinamento naturale delle chiavi oppure secondo un comparatore specifico fornito al momento della creazione della mappa. La sua unica sottointerfaccia diretta nel Collections Framework, NavigableMap, aggiunge metodi che forniscono operazioni di navigazione più avanzate per manipolare le chiavi della mappa, come ottenere la chiave più vicina a un determinato valore oppure attraversare la mappa in ordine crescente o decrescente.

In pratica, utilizziamo comunemente NavigableMap anziché SortedMap, poiché entrambe le classi che implementano SortedMap nel Collections Framework lo fanno indirettamente (TreeMap implementa NavigableMap e ConcurrentSkipListMap implementa ConcurrentNavigableMap). NavigableMap offre qualcosa in più in termini di funzionalità, fornendo metodi specifici per navigare nella mappa, in modo analogo a quanto NavigableSet fornisce per gli insiemi.


Questo articolo è un adattamento di contenuti del libro Orientação a Objetos com Java, di Eduardo Kessler Piveta