1. 概要

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

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

2. Mavenの依存関係

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

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

ライブラリの最新バージョンは、MavenCentralリポジトリにあります。

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<String, Integer> 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の例

次に、 mapIterator()メソッドを使用してMapIterator を取得します。これは、配列namesおよびagesで定義されているランナーの順序を保持する方法を示しています。

@Test
public void givenALinkedMap_whenIteratedWithMapIterator_thenPreservesOrder() {
    OrderedMapIterator<String, Integer> 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. 要素の削除

最後に、要素をインデックスまたはオブジェクトで削除する方法を確認しましょう。

@Test
public void givenALinkedMap_whenElementRemoved_thenSizeDecrease() {
    LinkedMap<String, Integer> lmap 
      = (LinkedMap<String, Integer>) 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インターフェースの双方向反復およびその他のメソッドを許可することで改良されています。

どちらの実装も、OrderedMapインターフェースの外部にある3つのメソッドを提供します

  • asList() –タイプのリストを取得しますリスト (どこ K キーのタイプです)マップの順序を保持します
  • get(int index) –インターフェイスで提供されるメソッド get(Object o)とは対照的に、位置indexで要素を取得します
  • indexOf(Object o) –順序付けられたマップ内のオブジェクトoのインデックスを取得します

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

@Test
public void givenALinkedMap_whenConvertedToList_thenMatchesKeySet() {
    LinkedMap<String, Integer> lmap 
      = (LinkedMap<String, Integer>) this.runnersLinkedMap;
    
    List<String> listKeys = new ArrayList<>();
    listKeys.addAll(this.runnersLinkedMap.keySet());
    List<String> linkedMap = lmap.asList();
 
    assertEquals(listKeys, linkedMap);
}

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

@Test
public void givenALinkedMap_whenSearchByIndexIsUsed_thenMatchesConstantArray() {
    LinkedMap<String, Integer> lmap 
      = (LinkedMap<String, Integer>) 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インターフェイスとその主要なメソッドおよび実装を確認しました。

詳細については、 ApacheCommonsCollectionsライブラリのJavaDocを参照してください。

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