1. 概要

map()および flatMap() APIは、関数型言語に由来します。 Java 8では、オプションストリームおよび CompleteableFuture にあります(ただし、名前は少し異なります)。

Streams はオブジェクトのシーケンスを表しますが、オプションは存在または不在の値を表すクラスです。 他の集約操作の中には、 map()メソッドと flatMap()メソッドがあります。

両方が同じリターンタイプを持っているという事実にもかかわらず、それらはかなり異なります。 ストリームとオプションの例をいくつか分析して、これらの違いを説明しましょう。

2. オプションのマップとフラットマップ

map()メソッドはオプションでうまく機能します—関数が必要な正確な型を返す場合:

Optional<String> s = Optional.of("test");
assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));

ただし、より複雑なケースでは、オプションも返す関数が与えられる場合があります。 このような場合、 map()を使用すると、 map()実装が内部で追加のラッピングを行うため、ネストされた構造になります。

この状況をよりよく理解するために、別の例を見てみましょう。

assertEquals(Optional.of(Optional.of("STRING")), 
  Optional
  .of("string")
  .map(s -> Optional.of("STRING")));

ご覧のとおり、ネストされた構造になりますオプション >> 。 それは機能しますが、使用するのはかなり面倒であり、追加のnull安全性を提供しないため、フラットな構造を維持することをお勧めします。

それがまさにflatMap()が私たちに役立つことです。

assertEquals(Optional.of("STRING"), Optional
  .of("string")
  .flatMap(s -> Optional.of("STRING")));

3. ストリームのマップとフラットマップ

どちらの方法も、オプションで同様に機能します。

The 地図() メソッドは、基になるシーケンスをストリームインスタンス、一方、 flatMap() メソッドはネストを回避することができますストリーム >> 構造。

ここで、 map()は、 toUpperCase()メソッドを入力Streamの要素に適用した結果で構成されるStreamを生成します。 :

List<String> myList = Stream.of("a", "b")
  .map(String::toUpperCase)
  .collect(Collectors.toList());
assertEquals(asList("A", "B"), myList);

map()は、このような単純なケースで非常にうまく機能します。 しかし、入力としてのリストのリストなど、もっと複雑なものがある場合はどうでしょうか。

それがどのように機能するか見てみましょう:

List<List<String>> list = Arrays.asList(
  Arrays.asList("a"),
  Arrays.asList("b"));
System.out.println(list);

このスニペットは、リスト [[a]、[b]]のリストを出力します。

次に、 flatMap()を使用しましょう。

System.out.println(list
  .stream()
  .flatMap(Collection::stream)
  .collect(Collectors.toList()));

このようなスニペットの結果は、 [a、b]にフラット化されます。

T he flatMap()メソッドは、最初に Stream of StreamsStreamにフラット化します。文字列(平坦化の詳細については、この記事を参照してください)。 その後は、 map()メソッドと同様に機能します。

4. 結論

Java 8は、関数型言語で元々使用されていた map()および flatMap()メソッドを使用する機会を提供します。

StreamsおよびOptionalsでそれらを呼び出すことができます。 これらのメソッドは、提供されているマッピング関数を適用することにより、マップされたオブジェクトを取得するのに役立ちます。

いつものように、この記事の例はGitHubから入手できます。