ストリームを使用してマップを操作する

1. 前書き

このチュートリアルでは、使用方法の例をいくつか紹介します-hashmap [Map] __https://www.baeldung.com/java-hashmap [s]。 これらの演習の一部は、双方向の_Map_データ構造を使用して解決できることは注目に値しますが、ここでは機能的なアプローチに興味があります。
最初に、_Maps_および__Stream__sを操作するために使用する基本的な考え方を説明します。 次に、__Stream__sを使用した_Maps_とその具体的なソリューションに関連するいくつかの異なる問題を示します。

2.  基本アイデア

注目すべき主なことは、__ Stream__sが_Collection_から簡単に取得できる要素のシーケンスであることです。
_Maps_の構造は異なり、キーから値へのマッピングがあり、シーケンスはありません。 これは、a__Map_構造を異なるシーケンスに変換できず、Stream APIで自然な方法で作業できることを意味しません。
_Map_から異なる__Collection__sを取得する方法を見てみましょう。これを_Stream_にピボットできます。
Map<String, Integer> someMap = new HashMap<>();
キーと値のペアのセットを取得できます。
Set<Map.Entry<String, Integer>> entries = someMap.entrySet();
_Map_に関連付けられたキーセットを取得することもできます。
Set<String> keySet = someMap.keySet();
または、値のセットを直接操作することもできます。
Collection<Integer> values = someMap.values();
これらはそれぞれ、ストリームを取得してコレクションを処理するためのエントリポイントを提供します。
Stream<Map.Entry<String, Integer>> entriesStream = entries.stream();
Stream<Integer> valuesStream = values.stream();
Stream<String> keysStream = keySet.stream();

3. Streamsを使用して_Map_’sキーを取得する

3.1. 入力データ

_Map_があるとします:
Map<String, String> books = new HashMap<>();
books.put("978-0201633610", "Design patterns : elements of reusable object-oriented software");
books.put("978-1617291999", "Java 8 in Action: Lambdas, Streams, and functional-style programming");
books.put("978-0134685991", "Effective Java");
「Effective Java」というタイトルの本のISBNを見つけることに興味があります。

3.2. マッチを取得する

本のタイトルが_Map_に存在しないため、関連するISBNがないことを示したいと考えています。 ** https://www.baeldung.com/java-optional [_Optional_] ** __を使用してthat__を表現できます。
この例では、そのタイトルに一致する本のキーに興味があると仮定します。
Optional<String> optionalIsbn = books.entrySet().stream()
  .filter(e -> "Effective Java".equals(e.getValue()))
  .map(Map.Entry::getKey)
  .findFirst();

assertEquals("978-0134685991", optionalIsbn.get());
コードを分析しましょう。 最初に、前に見たように、_Map_ *から_entrySet_を取得します。
「有効なJava」というタイトルのエントリのみを検討するため、最初の中間操作はlink:/java-stream-filter-lambda[filter]になります。
  • _Map_エントリ全体ではなく、各エントリのキーに関心があります。*次のチェーンされた中間操作は、まさにそれを行います。探していたタイトルに一致するエントリのキー。

    *結果が1つだけ必要なため、_findFirst()_ *端末操作を適用できます。これにより、_Stream_の初期値が_Optional_オブジェクトとして提供されます。
    タイトルが存在しない場合を見てみましょう:
Optional<String> optionalIsbn = books.entrySet().stream()
  .filter(e -> "Non Existent Title".equals(e.getValue()))
  .map(Map.Entry::getKey).findFirst();

assertEquals(false, optionalIsbn.isPresent());

3.3. 複数の結果を取得する

ここで問題を変更して、1つではなく複数の結果を返す方法を見てみましょう。
複数の結果が返されるように、following_Map_に次の本を追加しましょう。
books.put("978-0321356680", "Effective Java: Second Edition");
したがって、「Effective Java」で始まる_all_本を検索すると、複数の結果が返されます。
List<String> isbnCodes = books.entrySet().stream()
  .filter(e -> e.getValue().startsWith("Effective Java"))
  .map(Map.Entry::getKey)
  .collect(Collectors.toList());

assertTrue(isbnCodes.contains("978-0321356680"));
assertTrue(isbnCodes.contains("978-0134685991"));
この場合、フィルター条件を置き換えて、_String_の同等性を比較する代わりに、_Map_の値が「Effective Java」で始まるかどうかを検証します。
今回は、最初の結果を選択するのではなく、結果を_収集_し、一致するものを_List_に入れます。

4. Streamsを使用して_Map_‘s値を取得する

それでは、マップに関する別の問題に焦点を当てましょう。
元の_Map_を使用しましょう。 ISBNが「978-0」で始まるタイトルを探します。
List<String> titles = books.entrySet().stream()
  .filter(e -> e.getKey().startsWith("978-0"))
  .map(Map.Entry::getValue)
  .collect(Collectors.toList());

assertEquals(2, titles.size());
assertTrue(titles.contains("Design patterns : elements of reusable object-oriented software"));
assertTrue(titles.contains("Effective Java"));
*このソリューションは、以前の一連の問題に対するソリューションに似ています。エントリセットをストリーミングしてから、フィルタリング、マッピング、および収集します。*
前と同じように、最初の一致のみを返したい場合、_List_ですべての結果を収集する代わりに、_map_メソッドが_findFirst()_メソッドを呼び出した後にできます。

5. 結論

機能的な方法で_Map_を処理する方法を示しました__.__
特に、関連するコレクションを使用して__Map__sに切り替えると、__ Stream__sを使用した処理がはるかに簡単かつ直感的になることがわかりました。
そして、もちろん、すべての例はhttps://github.com/eugenp/tutorials/tree/master/java-streams[GitHubプロジェクト]にあります。