1. 简介
在本篇教程中,我们将深入探讨 Apache Commons Collections 库中提供的 MultiValuedMap
接口。
✅ MultiValuedMap
提供了一种简洁的 API,用于在 Java 中将每个键映射到一个值集合。它是 org.apache.commons.collections4.MultiMap
的继任者,后者在 Commons Collections 4.1 中已被标记为废弃。
2. Maven 依赖
对于使用 Maven 的项目,我们需要添加如下依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0-M2</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
方法可以获取所有键值对的集合:
Collection<Map.Entry<String, String>> entries = map.entries();
4.3. 获取所有键
有两种方式获取所有的键:
使用 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. 获取所有值
使用 values
方法可以获取所有值组成的集合:
Collection<String> values = map.values();
assertThat(values).contains("apple", "orange", "car", "bike");
5. 从 MultiValuedMap 中删除元素
接下来我们看看如何从 MultiValuedMap
中删除元素。
5.1. 删除某个键的所有值
使用 remove
方法可以删除某个键对应的所有值,并返回这些值的集合:
Collection<String> removedValues = map.remove("fruits");
assertThat(map.containsKey("fruits")).isFalse();
assertThat(removedValues).contains("apple", "orange");
5.2. 删除某个键值对
如果只想删除某个键对应的某个特定值,可以使用 removeMapping
方法:
boolean isRemoved = map.removeMapping("fruits","apple");
assertThat(map.containsMapping("fruits","apple")).isFalse();
5.3. 清空所有映射
使用 clear
方法可以清空整个 MultiValuedMap
:
map.clear();
assertThat(map.isEmpty()).isTrue();
6. 检查 MultiValuedMap 中的元素
以下是常用的检查方法。
6.1. 判断某个键是否存在
使用 containsKey
方法:
assertThat(map.containsKey("vehicles")).isTrue();
6.2. 判断某个值是否存在
使用 containsValue
方法:
assertThat(map.containsValue("orange")).isTrue();
6.3. 判断某个键值对是否存在
使用 containsMapping
方法:
assertThat(map.containsMapping("fruits","orange")).isTrue();
6.4. 判断是否为空
使用 isEmpty
方法:
assertThat(map.isEmpty()).isFalse();
6.5. 获取映射数量
使用 size
方法获取所有值的总数:
assertEquals(4, map.size());
7. 常见实现类
Apache Commons Collections 提供了多种 MultiValuedMap
的实现。
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");
⚠️ 注意:该类不是线程安全的,多线程环境下需要手动同步。
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");
可以看到,重复的值被自动去重。
⚠️ 同样地,该类也不是线程安全的。
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
}
❌ 任何修改操作都会抛出 UnsupportedOperationException
。
8. 总结
我们介绍了 Apache Commons Collections 中 MultiValuedMap
接口的各种常用方法,并演示了几种常见的实现类。在实际开发中,如果需要一个键映射多个值的场景,MultiValuedMap
是一个简单粗暴又实用的选择。