1. 概述
在这个快速教程中,我们将了解Apache Commons Collections库中提供的MultiValuedMap接口。
MultiValuedMap提供了一个简单的API,用于将每个键映射到Java中的值集合。它是org.apache.commons.collections4.MultiMap的继承者,后者在Commons Collection 4.1中被弃用。
2. Maven依赖
对于Maven项目,我们需要添加[commons-collections4](https://search.maven.org/classic/#search | ga | 1 | g%3A”org.apache.commons”ANDa%3A”commons-collections4”)依赖: |
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.2</version>
</dependency>
3. 将元素添加到MultiValuedMap中
我们可以使用put和putAll方法添加元素。
让我们从创建MultiValuedMap的实例开始:
MultiValuedMap<String, String> map = new ArrayListValuedHashMap<>();
接下来,让我们看看如何使用put方法一次添加一个元素:
map.put("fruits", "apple");
map.put("fruits", "orange");
此外,让我们使用putAll方法添加一些元素,该方法在一次调用中将一个键映射到多个元素:
map.putAll("vehicles", Arrays.asList("car", "bike"));
assertThat((Collection<String>) map.get("vehicles"))
.containsExactly("car", "bike");
4. 从MultiValuedMap中检索元素
MultiValuedMap提供检索键、值和键值映射的方法。让我们来看看其中的每一个。
4.1 获取键的所有值
要获取与键关联的所有值,我们可以使用get方法,它返回一个Collection:
assertThat((Collection<String>) map.get("fruits"))
.containsExactly("apple", "orange");
4.2 获取所有键值映射
或者,我们可以使用entries方法获取Map中包含的所有键值映射的Collection:
Collection<Map.Entry<String, String>> entries = map.entries();
4.3 获取所有键
有两种方法可以检索MultiValuedMap中包含的所有键。
让我们使用keys方法来获取键的MultiSet视图:
MultiSet<String> keys = map.keys();
assertThat(keys).contains("fruits", "vehicles");
或者,我们可以使用keySet方法获取键的Set视图:
Set<String> keys = map.keySet();
assertThat(keys).contains("fruits", "vehicles");
4.4 获取Map的所有值
最后,如果我们想要获取Map中包含的所有值的Collection视图,我们可以使用values方法:
Collection<String> values = map.values();
assertThat(values).contains("apple", "orange", "car", "bike");
5. 从MultiValuedMap中移除元素
现在,让我们看看删除元素和键值映射的所有方法。
5.1 删除映射到键的所有元素
首先,让我们看看如何使用remove方法删除与指定键关联的所有值:
Collection<String> removedValues = map.remove("fruits");
assertThat(map.containsKey("fruits")).isFalse();
assertThat(removedValues).contains("apple", "orange");
此方法返回已删除值的Collection视图。
5.2 删除单个键值映射
现在,假设我们有一个映射到多个值的键,但我们只想删除一个映射值,而保留其他值。我们可以使用removeMapping方法轻松做到这一点:
boolean isRemoved = map.removeMapping("fruits","apple");
assertThat(map.containsMapping("fruits","apple")).isFalse();
5.3 删除所有键值映射
最后,我们可以使用clear方法从Map中删除所有映射:
map.clear();
assertThat(map.isEmpty()).isTrue();
6. 检查MultiValuedMap中的元素
接下来,让我们看一下检查Map中是否存在指定键或值的各种方法。
6.1 检查键是否存在
要确定我们的Map是否包含指定键的映射,我们可以使用containsKey方法:
assertThat(map.containsKey("vehicles")).isTrue();
6.2 检查值是否存在
接下来,假设我们要检查Map中是否至少有一个键包含特定值的映射。我们可以使用containsValue方法来做到这一点:
assertThat(map.containsValue("orange")).isTrue();
6.3 检查键值映射是否存在
同样,如果我们想检查一个Map是否包含特定键值对的映射,我们可以使用containsMapping方法:
assertThat(map.containsMapping("fruits","orange")).isTrue();
6.4 检查Map是否为空
要检查Map是否根本不包含任何键值映射,我们可以使用isEmpty方法:
assertThat(map.isEmpty()).isFalse;
6.5 检查Map的大小
最后,我们可以使用size方法来获取Map的总大小。当一个Map具有多个值的键时,Map的总大小是所有键的所有值的计数:
assertEquals(4, map.size());
7. 实现
Apache Commons Collections库还提供了此接口的多种实现。让我们来看看它们。
7.1 ArrayListValuedHashMap
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");
现在,值得注意的是这个类不是线程安全的。因此,如果我们想从多个线程使用这个Map,我们必须确保使用适当的同步。
7.2 HashSetValuedHashMap
HashSetValuedHashMap使用HashSet来存储每个给定键的值。因此,它不允许重复的键值对。
让我们看一个简单的例子,其中我们添加相同的键值映射两次:
MultiValuedMap<String, String> map = new HashSetValuedHashMap<>();
map.put("fruits", "apple");
map.put("fruits", "apple");
assertThat((Collection<String>) map.get("fruits"))
.containsExactly("apple");
请注意,与前面使用ArrayListValuedHashMap的示例不同,HashSetValuedHashMap实现忽略了重复映射。
HashSetValuedHashMap类也不是线程安全的。
7.3 UnmodifiableMultiValuedMap
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
}
同样,值得注意的是,最终的put修改将导致UnsupportedOperationException。
8. 总结
我们已经看到Apache Commons Collections库中MultiValuedMap接口的各种方法。此外,我们还探索了一些流行的实现。
与往常一样,本教程的完整源代码可在GitHub上获得。