Guida ad Apache Commons MultiValuedMap

1. Panoramica

In questo breve tutorial, daremo uno sguardo all'interfaccia MultiValuedMap fornita nella libreria delle collezioni Apache Commons .

MultiValuedMap fornisce una semplice API per mappare ogni chiave a una raccolta di valori in Java. È il successore di org.apache.commons.collections4.MultiMap, che è stato deprecato in Commons Collection 4.1.

2. Dipendenza da Maven

Per i progetti Maven, dobbiamo aggiungere la dipendenza commons-collections4 :

 org.apache.commons commons-collections4 4.2 

3. Aggiunta di elementi in una MultiValuedMap

Possiamo aggiungere elementi usando i metodi put e putAll .

Cominciamo creando un'istanza di MultiValuedMap :

MultiValuedMap map = new ArrayListValuedHashMap();

Successivamente, vediamo come possiamo aggiungere elementi uno alla volta utilizzando il metodo put :

map.put("fruits", "apple"); map.put("fruits", "orange");

Inoltre, aggiungiamo alcuni elementi utilizzando il metodo putAll , che mappa una chiave a più elementi in una singola chiamata:

map.putAll("vehicles", Arrays.asList("car", "bike")); assertThat((Collection) map.get("vehicles")) .containsExactly("car", "bike");

4. Recupero di elementi da una MultiValuedMap

MultiValuedMap fornisce metodi per recuperare chiavi, valori e mappature valore-chiave. Diamo un'occhiata a ciascuno di questi.

4.1. Ottieni tutti i valori di una chiave

Per ottenere tutti i valori associati a una chiave, possiamo utilizzare il metodo get , che restituisce una Collection :

assertThat((Collection) map.get("fruits")) .containsExactly("apple", "orange");

4.2. Ottieni tutte le mappature valori-chiave

In alternativa, possiamo utilizzare il metodo delle voci per ottenere una raccolta di tutte le mappature valore-chiave contenute nella mappa:

Collection
    
      entries = map.entries();
    

4.3. Ottieni tutte le chiavi

Esistono due metodi per recuperare tutte le chiavi contenute in una MultiValuedMap.

Usiamo il metodo keys per ottenere una visualizzazione MultiSet delle chiavi:

MultiSet keys = map.keys(); assertThat(keys).contains("fruits", "vehicles");

In alternativa, possiamo ottenere una vista Set delle chiavi utilizzando il metodo keySet :

Set keys = map.keySet(); assertThat(keys).contains("fruits", "vehicles");

4.4. Ottieni tutti i valori di una mappa

Infine, se vogliamo ottenere una vista Collection di tutti i valori contenuti nella mappa, possiamo utilizzare il metodo dei valori :

Collection values = map.values(); assertThat(values).contains("apple", "orange", "car", "bike");

5. Rimozione di elementi da una MultiValuedMap

Ora, esaminiamo tutti i metodi per rimuovere elementi e mappature valore-chiave.

5.1. Rimuovi tutti gli elementi mappati su una chiave

Innanzitutto, vediamo come rimuovere tutti i valori associati a una chiave specificata utilizzando il metodo di rimozione :

Collection removedValues = map.remove("fruits"); assertThat(map.containsKey("fruits")).isFalse(); assertThat(removedValues).contains("apple", "orange");

Questo metodo restituisce una visualizzazione Raccolta dei valori rimossi.

5.2. Rimuovere una singola mappatura valore-chiave

Supponiamo ora di avere una chiave mappata su più valori, ma di voler rimuovere solo uno dei valori mappati, lasciando gli altri. Possiamo farlo facilmente usando il metodo removeMapping :

boolean isRemoved = map.removeMapping("fruits","apple"); assertThat(map.containsMapping("fruits","apple")).isFalse();

5.3. Rimuovi tutte le mappature valore-chiave

Infine, possiamo utilizzare il metodo clear per rimuovere tutte le mappature dalla mappa:

map.clear(); assertThat(map.isEmpty()).isTrue();

6. Controllo degli elementi da una MultiValuedMap

Successivamente, diamo un'occhiata ai vari metodi per verificare se una chiave o un valore specificato esiste nella nostra mappa.

6.1. Controlla se esiste una chiave

Per scoprire se la nostra mappa contiene una mappatura per una chiave specificata, possiamo utilizzare il metodo containsKey :

assertThat(map.containsKey("vehicles")).isTrue();

6.2. Controlla se esiste un valore

Successivamente, supponiamo di voler controllare se almeno una chiave nella nostra mappa contiene una mappatura per un particolare valore. Possiamo farlo usando il metodo containsValue :

assertThat(map.containsValue("orange")).isTrue();

6.3. Controlla se esiste una mappatura valore-chiave

Allo stesso modo, se vogliamo verificare se una mappa contiene una mappatura per una specifica coppia chiave e valore, possiamo utilizzare il metodo containsMapping :

assertThat(map.containsMapping("fruits","orange")).isTrue();

6.4. Controlla se una mappa è vuota

Per verificare se una mappa non contiene alcuna mappatura valore-chiave, possiamo utilizzare il metodo isEmpty :

assertThat(map.isEmpty()).isFalse;

6.5. Check the Size of a Map

Finally, we can use the size method to get the total size of the map. When a map has keys with multiple values, then the total size of the map is the count of all the values from all keys:

assertEquals(4, map.size());

7. Implementations

The Apache Commons Collections Library also provides multiple implementations of this interface. Let's have a look at them.

7.1. ArrayListValuedHashMap

An ArrayListValuedHashMap uses an ArrayList internally for storing the values associated with each key, so it allows duplicate key-values pairs:

MultiValuedMap map = new ArrayListValuedHashMap(); map.put("fruits", "apple"); map.put("fruits", "orange"); map.put("fruits", "orange"); assertThat((Collection) map.get("fruits")) .containsExactly("apple", "orange", "orange");

Now, it's worth noting that this class is not thread-safe. Therefore, if we want to use this map from multiple threads, we must be sure to use proper synchronization.

7.2. HashSetValuedHashMap

A HashSetValuedHashMap uses a HashSet for storing the values for each given key. Therefore, it doesn't allow duplicate key-value pairs.

Let's see a quick example, where we add the same key-value mapping twice:

MultiValuedMap map = new HashSetValuedHashMap(); map.put("fruits", "apple"); map.put("fruits", "apple"); assertThat((Collection) map.get("fruits")) .containsExactly("apple");

Notice how, unlike our previous example that used ArrayListValuedHashMap, the HashSetValuedHashMap implementation ignores the duplicate mapping.

The HashSetValuedHashMapclass is also not thread-safe.

7.3. UnmodifiableMultiValuedMap

L'UnmodifiableMultiValuedMap è una classe decoratrice che è utile quando abbiamo bisogno di un'istanza immutabile di un MultiValuedMap - che è, non dovrebbe consentire ulteriori modifiche:

@Test(expected = UnsupportedOperationException.class) public void givenUnmodifiableMultiValuedMap_whenInserting_thenThrowingException() { MultiValuedMap map = new ArrayListValuedHashMap(); map.put("fruits", "apple"); map.put("fruits", "orange"); MultiValuedMap immutableMap = MultiMapUtils.unmodifiableMultiValuedMap(map); immutableMap.put("fruits", "banana"); // throws exception }

E ancora, vale la pena notare che la modifica del put finale comporterà un'eccezione UnsupportedOperationException .

8. Conclusione

Abbiamo visto vari metodi dell'interfaccia MultiValuedMap dalla libreria delle collezioni Apache Commons. Inoltre, abbiamo esplorato alcune implementazioni popolari.

E, come sempre, il codice sorgente completo è disponibile su Github.