Contents

Apache Commons Collections MapUtils类简介

1. 简介

MapUtils是 Apache Commons Collections 项目中可用的工具之一。

简单地说,它提供了实用方法和装饰器来处理java.util.Mapjava.util.SortedMap实例。

2. 设置

让我们从添加依赖项 开始:

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

3. 实用方法

3.1. 从Array创建Map

现在,让我们设置用于创建Map的数组:

public class MapUtilsTest {
    private String[][] color2DArray = new String[][] {
        {"RED", "#FF0000"},
        {"GREEN", "#00FF00"},
        {"BLUE", "#0000FF"}
    };
    private String[] color1DArray = new String[] {
        "RED", "#FF0000",
        "GREEN", "#00FF00",
        "BLUE", "#0000FF"
    };
    private Map<String, String> colorMap;
    //...
}

让我们看看如何从二维数组创建Map:

@Test
public void whenCreateMapFrom2DArray_theMapIsCreated() {
    this.colorMap = MapUtils.putAll(
      new HashMap<>(), this.color2DArray);
    assertThat(
      this.colorMap, 
      is(aMapWithSize(this.color2DArray.length)));
    
    assertThat(this.colorMap, hasEntry("RED", "#FF0000"));
    assertThat(this.colorMap, hasEntry("GREEN", "#00FF00"));
    assertThat(this.colorMap, hasEntry("BLUE", "#0000FF"));
}

我们也可以使用一维数组。在这种情况下,数组被视为备用索引中的键和值:

@Test
public void whenCreateMapFrom1DArray_theMapIsCreated() {
    this.colorMap = MapUtils.putAll(
      new HashMap<>(), this.color1DArray);
    
    assertThat(
      this.colorMap, 
      is(aMapWithSize(this.color1DArray.length / 2)));
    assertThat(this.colorMap, hasEntry("RED", "#FF0000"));
    assertThat(this.colorMap, hasEntry("GREEN", "#00FF00"));
    assertThat(this.colorMap, hasEntry("BLUE", "#0000FF"));
}

3.2. 打印Map的内容

很多时候,在调试或调试日志中,我们想打印整个Map:

@Test
public void whenVerbosePrintMap_thenMustPrintFormattedMap() {
    MapUtils.verbosePrint(System.out, "Optional Label", this.colorMap);
}

结果:

Optional Label = 
{
    RED = #FF0000
    BLUE = #0000FF
    GREEN = #00FF00
}

我们还可以使用*debugPrint()*额外打印值的数据类型。

3.3. 获取值

MapUtils提供了一些方法,用于以null安全的方式从给定键的映射中提取值。

例如,getString()Map中获取一个StringString值是通过toString()获得的。如果值为null或转换失败,我们可以选择指定要返回的默认值:

@Test
public void whenGetKeyNotPresent_thenMustReturnDefaultValue() {
    String defaultColorStr = "COLOR_NOT_FOUND";
    String color = MapUtils
      .getString(this.colorMap, "BLACK", defaultColorStr);
    
    assertEquals(color, defaultColorStr);
}

请注意,这些方法是null安全的,即它们可以安全地处理null map 参数:

@Test
public void whenGetOnNullMap_thenMustReturnDefaultValue() {
    String defaultColorStr = "COLOR_NOT_FOUND";
    String color = MapUtils.getString(null, "RED", defaultColorStr);
    
    assertEquals(color, defaultColorStr);
}

即使地图为null ,这里的颜色也会得到COLOR_NOT_FOUND的值。

3.4. 反转Map

我们还可以轻松地反转Map:

@Test
public void whenInvertMap_thenMustReturnInvertedMap() {
    Map<String, String> invColorMap = MapUtils.invertMap(this.colorMap);
    int size = invColorMap.size();
    Assertions.assertThat(invColorMap)
      .hasSameSizeAs(colorMap)
      .containsKeys(this.colorMap.values().toArray(new String[] {}))
      .containsValues(this.colorMap.keySet().toArray(new String[] {}));
}

这会将colorMap反转为:

{
    #00FF00 = GREEN
    #FF0000 = RED
    #0000FF = BLUE
}

如果源映射为多个键关联相同的值,则在反转后,其中一个值将随机成为键。

3.5. 空和空检查

如果Mapnull或为空,isEmpty()方法返回true

safeAddToMap()方法防止向Map 添加空元素。

4. 装饰器

这些方法为Map添加了额外的功能。

在大多数情况下,最好不要存储对装饰 Map 的引用。

4.1. 固定大小的Map

*fixedSizeMap()*返回由给定地图支持的固定大小地图。元素可以更改,但不能添加或删除:

@Test(expected = IllegalArgumentException.class)
public void whenCreateFixedSizedMapAndAdd_thenMustThrowException() {
    Map<String, String> rgbMap = MapUtils
      .fixedSizeMap(MapUtils.putAll(new HashMap<>(), this.color1DArray));
    
    rgbMap.put("ORANGE", "#FFA500");
}

4.2. predicatedMap

predicatedMap()方法返回一个Map确保所有持有的元素与提供的谓词匹配:

@Test(expected = IllegalArgumentException.class)
public void whenAddDuplicate_thenThrowException() {
    Map<String, String> uniqValuesMap 
      = MapUtils.predicatedMap(this.colorMap, null, 
        PredicateUtils.uniquePredicate());
    
    uniqValuesMap.put("NEW_RED", "#FF0000");
}

在这里,我们使用PredicateUtils.uniquePredicate()为值指定谓词。任何将重复值插入此映射的尝试都将导致java.lang非法参数异常

我们可以通过实现Predicate接口来实现自定义谓词。

4.3. lazyMap

*lazyMap()*返回一个映射,其中值在请求时被初始化。

如果传递给此映射的Map.get(Object)方法的键在映射中不存在,则Transformer实例将用于创建将与请求的键关联的新对象:

@Test
public void whenCreateLazyMap_theMapIsCreated() {
    Map<Integer, String> intStrMap = MapUtils.lazyMap(
      new HashMap<>(),
      TransformerUtils.stringValueTransformer());
    
    assertThat(intStrMap, is(anEmptyMap()));
    
    intStrMap.get(1);
    intStrMap.get(2);
    intStrMap.get(3);
    
    assertThat(intStrMap, is(aMapWithSize(3)));
}