Contents

Apache Commons Collections 库 MultivaluedMap接口简介

1.概述

在本快速教程中,我们将了解 Apache Commons Collections 库中提供的MultiValuedMap 接口。

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

2. Maven依赖

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

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

3. 将元素添加到MultiValuedMap

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

让我们从创建 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

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

4.3. 获取所有key

有两种方法可以检索 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. 获取所有值

最后,如果我们想要获取地图中包含的所有值的 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.clear();
assertThat(map.isEmpty()).isTrue();

6. 检查MultiValuedMap中的元素

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

6.1. 检查key是否存在

要确定我们的地图是否包含指定键的映射,我们可以使用 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 Library 也提供了这个接口的多种实现。让我们来看看它们。

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");

请注意,与我们之前使用 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