1. 概要

キーと値のペアのコレクションを格納するためにマップを使用することがよくあります。 次に、ある時点で、それらを反復する必要があることがよくあります。

このチュートリアルでは、マップの反復のさまざまな方法を比較し、Map.Entryを使用することが有益な場合を強調します。 次に、Map.Entryを使用してタプルを作成する方法を学習します。 最後に、タプルの順序付きリストを作成します。

2. マップ反復の最適化

著者の名前をキーにした本のタイトルのマップがあるとします。

Map<String, String> map = new HashMap<>();

map.put("Robert C. Martin", "Clean Code");
map.put("Joshua Bloch", "Effective Java");

マップからすべてのキーと値を取得する2つの方法を比較してみましょう。

2.1. Map.keySetを使用する

まず、次のことを考慮してください。

for (String key : bookMap.keySet()) {
    System.out.println("key: " + key + " value: " + bookMap.get(key));
}

ここで、ループはkeySetを繰り返します。 キーごとに、Map.getを使用して対応する値を取得します。 これはマップ内のすべてのエントリを使用するための明白な方法ですが、エントリごとに2つの操作が必要です 1つは次のキーを取得し、もう1つはgetで値を検索します]。

マップ内のキーだけが必要な場合は、keySetが適切なオプションです。 ただし、キーと値の両方を取得するためのより高速な方法があります。

2.2. 代わりにMap.entrySetを使用する

entrySetを使用するように反復を書き直してみましょう。

for (Map.Entry<String, String> book: bookMap.entrySet()) {
    System.out.println("key: " + book.getKey() + " value: " + book.getValue());
}

この例では、ループはMap.Entryオブジェクトのコレクション上にあります。  Map.Entryは、キーと値の両方を1つのクラスにまとめて格納するため、1回の操作で両方を取得します

同じルールがJava8ストリーム操作を使用するにも適用されます。 entrySet を介したストリーミングと、 Entry オブジェクトの操作は、より効率的であり、必要なコードが少なくて済みます。

3. タプルの操作

タプルは、要素の数と順序が固定されているデータ構造です。 Map.Entry は、キーと値の2つの要素を格納するタプルであると考えることができます。 ただし、 Map.Entry はインターフェイスであるため、実装クラスが必要です。 このセクションでは、JDKによって提供される1つの実装AbstractMap.SimpleEntryについて説明します。

3.1. タプルの作成

まず、Bookクラスについて考えてみましょう。

public class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }
    ...

次に、ISBNをキーとして、 Book オブジェクトを値として、Map.Entryタプルを作成しましょう。

Map.Entry<String, Book> tuple;

最後に、AbstractMap.SimpleEntryを使用してタプルをインスタンス化します。

tuple = new AbstractMap.SimpleEntry<>("9780134685991", new Book("Effective Java 3d Edition", "Joshua Bloch"));

3.2. タプルの順序付きリストの作成

タプルを操作するときは、それらを順序付きリストとして持つと便利なことがよくあります。

まず、タプルのリストを定義します。

List<Map.Entry<String, Book>> orderedTuples = new ArrayList<>();

次に、リストにいくつかのエントリを追加しましょう。

orderedTuples.add(new AbstractMap.SimpleEntry<>("9780134685991", 
  new Book("Effective Java 3d Edition", "Joshua Bloch")));
orderedTuples.add(new AbstractMap.SimpleEntry<>("9780132350884", 
  new Book("Clean Code","Robert C Martin")));

3.3. マップとの比較

Map との違いを比較するために、既存のキーを使用して新しいエントリを追加しましょう。

orderedTuples.add(new AbstractMap.SimpleEntry<>("9780132350884", 
  new Book("Clean Code", "Robert C Martin")));

次に、リストを繰り返し処理して、すべてのキーと値を表示します。

for (Map.Entry<String, Book> tuple : orderedTuples) {
    System.out.println("key: " + tuple.getKey() + " value: " + tuple.getValue());
}

最後に、出力を見てみましょう。

key: 9780134685991 value: Book{title='Effective Java 3d Edition', author='Joshua Bloch'}
key: 9780132350884 value: Book{title='Clean Code', author='Robert C Martin'}
key: 9780132350884 value: Book{title='Clean Code', author='Robert C Martin'}

各キーが一意である必要がある基本的なマップとは異なり、重複するキーを持つことができることに注意してください。 これは、 List 実装を使用して、 SimpleEntry オブジェクトを格納したためです。つまり、すべてのオブジェクトが互いに独立しています。

3.4. エントリオブジェクトのリスト

Entry の目的は、一般的なタプルとして機能することではないことに注意してください。 ライブラリクラスは、多くの場合、この目的のために汎用ペアクラスを提供します。

ただし、 Map のデータを準備しているとき、またはそこからデータを抽出しているときに、エントリのリストを一時的に操作する必要がある場合があります。

4. 結論

この記事では、マップのキーを反復処理する代わりに、Map.entrySetについて説明しました。

次に、Map.Entryをタプルとして使用する方法を確認しました。

最後に、順序付けられたタプルのリストを作成し、その違いを基本的なMapと比較しました。

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