Guía de Apache Commons MultiValuedMap

1. Información general

En este tutorial rápido, veremos la interfaz MultiValuedMap proporcionada en la biblioteca Apache Commons Collections .

MultiValuedMap proporciona una API simple para mapear cada clave a una colección de valores en Java. Es el sucesor de org.apache.commons.collections4.MultiMap, que quedó obsoleto en Commons Collection 4.1.

2. Dependencia de Maven

Para los proyectos de Maven, necesitamos agregar la dependencia commons-collections4 :

 org.apache.commons commons-collections4 4.2 

3. Agregar elementos a un mapa de valores múltiples

Podemos agregar elementos usando los métodos put y putAll .

Comencemos creando una instancia de MultiValuedMap :

MultiValuedMap map = new ArrayListValuedHashMap();

A continuación, veamos cómo podemos agregar elementos uno a la vez usando el método put :

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

Además, agreguemos algunos elementos usando el método putAll , que asigna una clave a múltiples elementos en una sola llamada:

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

4. Recuperación de elementos de un mapa de valores múltiples

MultiValuedMap proporciona métodos para recuperar claves, valores y asignaciones de clave-valor. Echemos un vistazo a cada uno de ellos.

4.1. Obtenga todos los valores de una clave

Para obtener todos los valores asociados con una clave, podemos usar el método get , que devuelve una colección :

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

4.2. Obtener todas las asignaciones de valores-clave

O podemos usar el método de entradas para obtener una colección de todas las asignaciones de clave-valor contenidas en el mapa:

Collection
    
      entries = map.entries();
    

4.3. Obtener todas las claves

Hay dos métodos para recuperar todas las claves contenidas en un MultiValuedMap.

Usemos el método de claves para obtener una vista MultiSet de las claves:

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

Alternativamente, podemos obtener una vista de conjunto de las claves usando el método keySet :

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

4.4. Obtener todos los valores de un mapa

Finalmente, si queremos obtener una vista de Colección de todos los valores contenidos en el mapa, podemos usar el método de valores :

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

5. Eliminación de elementos de un mapa de valores múltiples

Ahora, veamos todos los métodos para eliminar elementos y asignaciones de valores clave.

5.1. Eliminar todos los elementos asignados a una clave

Primero, veamos cómo eliminar todos los valores asociados con una clave especificada usando el método remove :

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

Este método devuelve una vista de colección de los valores eliminados.

5.2. Eliminar una asignación de valor-clave única

Ahora, suponga que tenemos una clave asignada a varios valores, pero queremos eliminar solo uno de los valores asignados, dejando los demás. Podemos hacer esto fácilmente usando el método removeMapping :

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

5.3. Eliminar todas las asignaciones de valores-clave

Y finalmente, podemos usar el método clear para eliminar todas las asignaciones del mapa:

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

6. Comprobación de elementos de un mapa de valores múltiples

A continuación, echemos un vistazo a los diversos métodos para verificar si existe una clave o valor específico en nuestro mapa.

6.1. Compruebe si existe una clave

Para saber si nuestro mapa contiene un mapeo para una clave específica, podemos usar el método containsKey :

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

6.2. Compruebe si existe un valor

A continuación, suponga que queremos comprobar si al menos una clave en nuestro mapa contiene un mapeo para un valor particular. Podemos hacer esto usando el método containsValue :

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

6.3. Compruebe si existe una asignación de valores-clave

De manera similar, si queremos verificar si un mapa contiene un mapeo para un par de clave y valor específico, podemos usar el método containsMapping :

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

6.4. Compruebe si un mapa está vacío

Para comprobar si un mapa no contiene ningún mapeo clave-valor, podemos usar el método 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. UnmodificableMultiValuedMap

El UnmodifiableMultiValuedMap es una clase decoradora que es útil cuando necesitamos una instancia inmutable de un MultiValuedMap - que es, no debe permitir que otras modificaciones:

@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 }

Y de nuevo, vale la pena señalar que la modificación de la final de venta se traducirá en un UnsupportedOperationException .

8. Conclusión

Hemos visto varios métodos de la interfaz MultiValuedMap de la biblioteca Apache Commons Collections. Además, hemos explorado algunas implementaciones populares.

Y, como siempre, el código fuente completo está disponible en Github.