Apache Commons CollectionsのOrderedMap

Apache CommonsコレクションOrderedMap

1. 概要

Apache Commons Collections libraryは、Javaコレクションフレームワークを補完する便利なクラスを提供します。

この記事では、java.util.Mapを拡張するインターフェースOrderedMapを確認します。

2. メーベン依存

最初に行う必要があるのは、pom.xmlにMaven依存関係を追加することです。


    org.apache.commons
    commons-collections4
    4.1

ライブラリの最新バージョンはMaven Central repositoryにあります。

3. OrderedMapプロパティ

簡単に言えば、OrderedMapインターフェースを実装するマップは次のとおりです。

  • セットはソートされていませんが、キーのセットの順序を維持します

  • 次の方法で両方向に反復できます:firstKey()nextKey()、またはlastKey()previousKey()

  • MapIteratorでトラバースできます(ライブラリによっても提供されます)

  • 要素を検索、変更、削除、または置換するメソッドを提供します

4. OrderedMapの使用

テストクラスでランナーのOrderedMapとその年齢を設定しましょう。 ライブラリで提供されるOrderedMap実装の1つであるLinkedMapを使用します。

まず、マップをロードして値の順序を確認するために使用するランナーと年齢の配列を設定しましょう。

public class OrderMapUnitTest {
    private String[] names = {"Emily", "Mathew", "Rose", "John", "Anna"};
    private Integer[] ages = {37, 28, 40, 36, 21};
    private LinkedMap runnersLinkedMap;

    //...
}

それでは、マップを初期化しましょう。

@Before
public void createRunners() {
    this.runnersLinkedMap = new LinkedMap<>();

    for (int i = 0; i < RUNNERS_COUNT; i++) {
        runners.put(this.names[i], this.ages[i]);
    }
}

4.1. 順方向反復

フォワードイテレータがどのように使用されるかを見てみましょう。

@Test
public void givenALinkedMap_whenIteratedForwards_thenPreservesOrder() {
    String name = this.runnersLinkedMap.firstKey();
    int i = 0;
    while (name != null) {
        assertEquals(name, names[i]);
        name = this.runnersLinkedMap.nextKey(name);
        i++;
    }
}

最後のキーに到達すると、メソッドnextKey()null値を返すことに注意してください。

4.2. 後方反復

最後のキーから始めて、繰り返してみましょう。

@Test
public void givenALinkedMap_whenIteratedBackwards_thenPreservesOrder() {
    String name = this.runnersLinkedMap.lastKey();
    int i = RUNNERS_COUNT - 1;
    while (name != null) {
        assertEquals(name, this.names[i]);
        name = this.runnersLinkedMap.previousKey(name);
        i--;
    }
}

最初のキーに到達すると、previousKey()メソッドはnullを返します。

4.3. MapIteratorの例

次に、配列namesおよびagesで定義されているランナーの順序を保持する方法を示すために、use the mapIterator() method to obtain a MapIteratorを使用します。

@Test
public void givenALinkedMap_whenIteratedWithMapIterator_thenPreservesOrder() {
    OrderedMapIterator runnersIterator
      = this.runnersLinkedMap.mapIterator();

    int i = 0;
    while (runnersIterator.hasNext()) {
        runnersIterator.next();

        assertEquals(runnersIterator.getKey(), this.names[i]);
        assertEquals(runnersIterator.getValue(), this.ages[i]);
        i++;
    }
}

4.4. 要素を削除する

最後に、an element can be removed by index or by objectがどのようになっているのかを確認しましょう。

@Test
public void givenALinkedMap_whenElementRemoved_thenSizeDecrease() {
    LinkedMap lmap
      = (LinkedMap) this.runnersLinkedMap;

    Integer johnAge = lmap.remove("John");

    assertEquals(johnAge, new Integer(36));
    assertEquals(lmap.size(), RUNNERS_COUNT - 1);

    Integer emilyAge = lmap.remove(0);

    assertEquals(emilyAge, new Integer(37));
    assertEquals(lmap.size(), RUNNERS_COUNT - 2);
}

5. 提供された実装

現在、ライブラリのバージョン4.1には、OrderedMapインターフェイスの2つの実装(ListOrderedMapLinkedMap)があります。

ListOrderedMapは、java.util.Listを使用してキーセットの順序を追跡します。 これはOrderedMapのデコレータであり、静的メソッドListOrderedMap.decorate(Map map)を使用して任意のMapから作成できます。

LinkedMapHashMapに基づいており、双方向反復およびOrderedMapインターフェイスの他のメソッドを許可することで改善されています。

Both implementations also provide three methods that are outside the OrderedMap interface

  • asList() –マップの順序を保持するタイプList<K>Kはキーのタイプ)のリストを取得します

  • get(int index) –インターフェイスで提供されるメソッドget(Object o)とは対照的に、位置indexで要素を取得します

  • indexOf(Object o) –順序付けられたマップ内のオブジェクトoのインデックスを取得します

OrderedMapLinkedMapにキャストして、asList()メソッドを使用できます。

@Test
public void givenALinkedMap_whenConvertedToList_thenMatchesKeySet() {
    LinkedMap lmap
      = (LinkedMap) this.runnersLinkedMap;

    List listKeys = new ArrayList<>();
    listKeys.addAll(this.runnersLinkedMap.keySet());
    List linkedMap = lmap.asList();

    assertEquals(listKeys, linkedMap);
}

次に、LinkedMap実装のメソッドindexOf(Object o)およびget(int index)の機能を確認できます。

@Test
public void givenALinkedMap_whenSearchByIndexIsUsed_thenMatchesConstantArray() {
    LinkedMap lmap
      = (LinkedMap) this.runnersLinkedMap;

    for (int i = 0; i < RUNNERS_COUNT; i++) {
        String name = lmap.get(i);

        assertEquals(name, this.names[i]);
        assertEquals(lmap.indexOf(this.names[i]), i);
    }
}

6. 結論

このクイックチュートリアルでは、OrderedMapインターフェースとその主要なメソッドおよび実装を確認しました。

詳細については、the JavaDoc of the Apache Commons Collections libraryを参照してください。

いつものように、この記事の完全なテストクラスには、LinkedMapListOrderedMapの両方を使用した同様のテストケースが含まれており、GitHub projectからダウンロードできます。