1. 序章

MapUtils は、ApacheCommonsCollectionsプロジェクトで利用可能なツールの1つです。

簡単に言えば、java.util.Mapおよびjava.util.SortedMapインスタンスを操作するためのユーティリティメソッドとデコレータを提供します。

2. 設定

依存関係を追加することから始めましょう:

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

3. ユーティリティメソッド

3.1. アレイからマップを作成する

次に、マップの作成に使用する配列を設定しましょう。

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;

    //...
}

2次元配列からマップを作成する方法を見てみましょう。

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

1次元配列を使用することもできます。 その場合、配列は代替インデックスのキーと値として扱われます。

@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. マップのコンテンツを印刷する

デバッグ中またはデバッグログに何度も、マップ全体を印刷したいと思います。

@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からStringを取得します。 String の値は、 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マップパラメータを安全に処理できます。

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

ここで、マップが null であっても、colorCOLOR_NOT_FOUNDとして値を取得します。

3.4. マップを反転します

マップを簡単に反転することもできます。

@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
}

ソースマップが複数のキーに同じ値を関連付ける場合、反転後、値の1つがランダムにキーになります。

3.5. ヌルおよび空のチェック

isEmpty()メソッドは、Mapnullまたは空の場合にtrueを返します。

safeAddToMap()メソッドは、Mapへのnull要素の追加を防ぎます。

4. デコレータ

これらのメソッドは、マップに追加機能を追加します。

ほとんどの場合、装飾されたMapへの参照を保存しないことをお勧めします。

4.1. 固定サイズマップ

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()メソッドは 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。IllegalArgumentExceptionが発生します。

Predicate インターフェースを実装することにより、カスタム述語を実装できます。

4.3. 怠惰なマップ

lazyMap()は、要求されたときに値が初期化されるマップを返します。

このマップのMap.get(Object)メソッドに渡されたキーがマップに存在しない場合、 Transformationr インスタンスを使用して、に関連付けられる新しいオブジェクトが作成されます。要求されたキー:

@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)));
}

5. 結論

このクイックチュートリアルでは、Apache Commons Collections MapUtils クラスについて説明し、さまざまな一般的なマップ操作を簡素化できるさまざまなユーティリティメソッドとデコレータについて説明しました。

いつものように、コードはGitHubから入手できます。