Guide to Apache Commons MultiValuedMap – Apache Commons MultiValuedMap指南

最后修改: 2019年 2月 21日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll have a look at the MultiValuedMap interface provided in the Apache Commons Collections library

在这个快速教程中,我们将看一下Apache Commons Collections库中提供的MultiValuedMap接口

MultiValuedMap provides a simple API for mapping each key to a collection of values in Java. It’s the successor to org.apache.commons.collections4.MultiMapwhich was deprecated in Commons Collection 4.1.

MultiValuedMap提供了一个简单的API,用于将每个键映射到Java中的值集合。它是org.apache.commons.collection4.MultiMap的继承者,后者在Commons Collection 4.1中被废弃。

2. Maven Dependency

2.Maven的依赖性

For Maven projects, we need to add the commons-collections4 dependency:

对于Maven项目,我们需要添加commons-collections4依赖项。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.2</version>
</dependency>

3. Adding Elements into a MultiValuedMap

3.向MultiValuedMap添加元素

We can add elements using the put and putAll methods.

我们可以使用putputAll方法添加元素。

Let’s start by creating an instance of MultiValuedMap:

让我们先创建一个MultiValuedMap的实例。

MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();

Next, let’s see how we can add elements one at a time using the put method:

接下来,让我们看看如何使用put方法一个一个地添加元素。

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

In addition, let’s add some elements using the putAll method, which maps a key to multiple elements in a single call:

此外,让我们使用putAll方法添加一些元素,该方法在一次调用中将一个键映射到多个元素。

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

4. Retrieving Elements from a MultiValuedMap

4.MultiValuedMap中检索元素

MultiValuedMap provides methods to retrieve keys, values, and key-value mappings. Let’s take a look at each of those.

MultiValuedMap提供了检索键、值和键值映射的方法。让我们来看看这些方法中的每一个。

4.1. Get All Values of a Key

4.1.获取一个键的所有值

To get all values associated with a key, we can use the get method, which returns a Collection:

要获得与一个键相关的所有值,我们可以使用 get 方法,它返回一个Collection

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

4.2. Get All Key-Value Mappings

4.2.获取所有键值映射

Or, we can use the entries method to get a Collection of all key-value mappings contained in the map:

或者,我们可以使用entries方法来获得一个Collection的地图中包含的所有键-值映射。

Collection<Map.Entry<String, String>> entries = map.entries();

4.3. Get All Keys

4.3.获取所有钥匙

There are two methods for retrieving all the keys contained in a MultiValuedMap.

有两种方法可以检索一个MultiValuedMap中包含的所有键。

Let’s use the keys method to get a MultiSet view of the keys:

让我们使用keys方法来获得MultiSet键的视图。

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

Alternatively, we can get a Set view of the keys using the keySet method:

另外,我们可以使用keySet方法得到一个Set的键的视图。

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

4.4. Get All Values of a Map

4.4.获取一个地图的所有值

Finally, if we want to get a Collection view of all values contained in the map, we can use the values method:

最后,如果我们想得到一个Collection地图中包含的所有值的视图,我们可以使用 values方法。

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

5. Removing Elements from a MultiValuedMap

5.MultiValuedMap中删除元素

Now, let’s look at all the methods for removing elements and key-value mappings.

现在,让我们看看删除元素和键值映射的所有方法。

5.1. Remove All Elements Mapped to a Key

5.1.移除映射到一个键的所有元素

First, let’s see how to remove all values associated with a specified key using the remove method:

首先,让我们看看如何使用 remove 方法来删除与指定键相关的所有值。

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

This method returns a Collection view of the removed values.

这个方法返回一个Collection的被移除的值的视图。

5.2. Remove a Single Key-Value Mapping

5.2.移除单个键值映射

Now, suppose we have a key mapped to multiple values, but we want to remove only one of the mapped values, leaving the others. We can easily do this using the removeMapping method:

现在,假设我们有一个键映射到多个值,但我们只想移除其中一个映射的值,留下其他的。我们可以使用removeMapping方法轻松做到这一点。

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

5.3. Remove All Key-Value Mappings

5.3.删除所有键值映射

And finally, we can use the clear method to remove all mappings from the map:

最后,我们可以使用clear方法来删除地图上的所有映射。

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

6. Checking Elements from a MultiValuedMap

6.检查来自MultiValuedMap的元素

Next, let’s take a look at the various methods for checking whether a specified key or value exists in our map.

接下来,让我们看一下检查指定的键或值是否存在于我们的地图中的各种方法。

6.1. Check If a Key Exists

6.1.检查一个键是否存在

To find out whether our map contains a mapping for a specified key, we can use the containsKey method:

为了找出我们的地图是否包含一个指定键的映射,我们可以使用containsKey方法。

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

6.2. Check If a Value Exists

6.2.检查一个值是否存在

Next, suppose we want to check if at least one key in our map contains a mapping for a particular value. We can do this using the containsValue method:

接下来,假设我们想检查我们的地图中是否至少有一个键包含一个特定值的映射。我们可以使用containsValue方法来做到这一点。

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

6.3. Check If a Key-Value Mapping Exists

6.3.检查是否存在一个键值映射

Similarly, if we want to check whether a map contains a mapping for a specific key and value pair, we can use the containsMapping method:

同样地,如果我们想检查一个地图是否包含一个特定键和值对的映射,我们可以使用 containsMapping方法。

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

6.4. Check If a Map Is Empty

6.4.检查地图是否是空的

To check if a map does not contain any key-value mappings at all, we can use the isEmpty method:

要检查一个地图是否完全不包含任何键值映射,我们可以使用isEmpty方法。

assertThat(map.isEmpty()).isFalse;

6.5. Check the Size of a Map

6.5.检查地图的大小

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:

最后,我们可以使用size方法来获得地图的总大小。当一个地图的键有多个值时,那么地图的总大小就是所有键的所有值的计数。

assertEquals(4, map.size());

7. Implementations

7.实施方案

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

Apache Commons集合库也提供了这个接口的多种实现。让我们来看看它们。

7.1. ArrayListValuedHashMap

7.1.ArrayListValuedHashMap

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

ArrayListValuedHashMap内部使用ArrayList来存储与每个键相关的值,所以它允许重复的键值对

MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();
map.put("fruits", "apple");
map.put("fruits", "orange");
map.put("fruits", "orange");
assertThat((Collection<String>) 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

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.

HashSetValuedHashMap使用HashSet来存储每个指定键的值。因此,它不允许重复的键-值对

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

让我们看一个快速的例子,我们把同一个键值映射添加两次。

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

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

请注意,与我们之前使用ArrayListValuedHashMap的例子不同,HashSetValuedHashMap实现忽略了重复的映射。

The HashSetValuedHashMap class is also not thread-safe.

HashSetValuedHashMap 类也不是线程安全的

7.3. UnmodifiableMultiValuedMap

7.3.UnmodifiableMultiValuedMap

The UnmodifiableMultiValuedMap is a decorator class that is useful when we need an immutable instance of a MultiValuedMap – that is, it shouldn’t allow further modifications:

UnmodifiableMultiValuedMap是一个装饰类,当我们需要一个MultiValuedMap的不可变的实例时,这个类很有用–也就是说,它不应该允许进一步修改。

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

And again, it’s worth noting that modifying the final put will result in an UnsupportedOperationException.

再说一遍,值得注意的是,修改最后的put将导致UnsupportedOperationException

8. Conclusion

8.结论

We’ve seen various methods of the MultiValuedMap interface from the Apache Commons Collections library. In addition, we’ve explored a few popular implementations.

我们已经看到了Apache Commons集合库中的MultiValuedMap接口的各种方法。此外,我们还探索了一些流行的实现。

And, as always, the full source code is available over on Github.

而且,像往常一样,完整的源代码可在Github上获得。