Java 8のmap()メソッドとflatMap()メソッドの違いは何ですか?


706

Java 8では、Stream.map()Stream.flatMap()メソッドの違いは何ですか?


55
タイプシグネチャは、全体像を物語っています。map :: Stream T -> (T -> R) -> Stream RflatMap :: Stream T -> (T -> Stream R) -> Stream R
Chris Martin

98
fwiw、これらの型シグネチャはJavaのようにも見えません。(私は知っています-しかし、それは「全体像」を告げるためにwrt map / flatMapは、新しく改善された「Java ++」に関する多くの知識を前提としています)
マイケル

16
@michaelその型シグネチャはJavaではなくHaskellのように見えます。しかし、実際のJava署名がこれ以上読みやすいかどうかは明らかではありません<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
スチュアートマークス

8
ハ、ええ、私は「実際のJava」について言及していました。C ++と同様に、現代のJavaは、90年代にそれを使い始めた人にはほとんど認識されません(私がそうであったように、両方の言語)。コメントに返信するだけで、そのメソッドシグネチャは「全体の話」をほとんど伝えません。少なくとも、追加の説明(またはコメンターの場合は翻訳)がなければ、それは不可能です。
マイケル

2
これは、と言うことですmapのマッパーラムダ戻りRflatMapのマッパーラムダ返すStreamR(をStream<R>)。flatMapのマッパーによって返されるストリームは効果的に連結されます。それ以外の場合は、両方mapflatMapリターンStream<R>。違いは何マッパーラムダリターン、であるRStream<R>
derekm 2018年

回答:


814

mapflatMapは両方に適用できStream<T>、両方ともを返しますStream<R>。違いは、map演算は各入力値に対して1つの出力値をflatMap生成するのに対し、演算は各入力値に対して任意の数(ゼロ以上)の値を生成することです。

これは、各操作の引数に反映されます。

map動作は、かかるFunction入力ストリーム内の各値のために呼び出され、出力ストリームに送信される1つの結果値を生成します。

flatMap操作は、概念的に一つの値を消費した値の任意の数を生成したい機能を取ります。ただし、Javaでは、メソッドはゼロまたは1つの値しか返せないため、メソッドが任意の数の値を返すのは面倒です。のマッパー関数flatMapが値を取り、配列またはListその後、出力に送信されます。これがストリームライブラリである場合、任意の数の戻り値を表す特に適切な方法は、マッパー関数自体がストリームを返すことです!マッパーによって返されたストリームからの値は、ストリームから排出され、出力ストリームに渡されます。マッパー関数の各呼び出しによって返される値の「塊」は、出力ストリームではまったく区別されないため、出力は「平坦化」されているといいます。

典型的な使用法は、マッパー関数が0の値を送信したい場合flatMapに返すStream.empty()か、またはStream.of(a, b, c)複数の値を返したい場合などです。ただし、もちろん、任意のストリームを返すことができます。


26
flatMap操作はフラットの正反対であるように私に聞こえます。繰り返しになりますが、コンピュータサイエンティストに任せて、用語の頭を変えてください。関数が「透過的」であるように、機能は何も見ることができず、結果だけが見えます。一方、プロセスを透過的にしたいと口語で言うとは、そのすべての部分を表示することを意味します。
coladict

45
@coladict別の視点から見てみてください。内部の仕組みを見ることができる透明なケースではありませんが、関数自体は透明であり、つまり見えません。再作業。この場合、「フラット」は「入れ子」の反対を指し、flatmapはフラット化によって1つの入れ子レベルを削除します。
Zefiro

7
@coladict「透明」なものは何年も頭を悩ませてきました。少なくとも他の1人が同じように感じていることを知ってうれしい。
Ashok Bijoy Debnath 2017

9
単一レベル構造に2レベルの構造を回してから来てフラット化、例のためにDICIの回答を参照してくださいstackoverflow.com/a/26684582/6012102
andrzej.szmukala

26
これがflatMapの最良の説明です。これにより、すべてがクリックされます。マッパーによって返されたストリームからの値は、ストリームから排出され、出力ストリームに渡されます。マッパー関数の各呼び出しによって返される値の「塊」は、出力ストリームではまったく区別されないため、出力は「平坦化」されているといいます。ありがとうございました!
neevek 2018年

464

Stream.flatMapは、その名前から推測できるように、mapflat操作の組み合わせです。つまり、まず要素に関数を適用し、次にそれを平坦化します。Stream.map関数をストリームに適用するだけで、ストリームをフラット化しません。

ストリームのフラット化の内容を理解するために、[ [1,2,3],[4,5,6],[7,8,9] ]「2つのレベル」のような構造を考えます。これを平坦化するということは、「1レベル」の構造に変換することを意味します[ 1,2,3,4,5,6,7,8,9 ]


5
シンプルで甘い
bluelurker

3
はは、公平を期すために、この質問がどれだけのトラフィックを獲得しているかを見て、私はまだ驚いています。もう1つの面白い観察は、私がこの回答を書いてほぼ5年であり、承認された回答が私の回答の1つにつき約2つの賛成票を獲得するというかなり一貫した賛成票のパターンがあったことです。驚くほど一貫しています。
Dici

1
これは容認された答えではないの
です。要点を直視し

233

より実用的な観点を得るために2つの例を挙げたいと思います:
マップを使用する最初の例:

@Test
public void convertStringToUpperCaseStreams() {
    List<String> collected = Stream.of("a", "b", "hello") // Stream of String 
            .map(String::toUpperCase) // Returns a stream consisting of the results of applying the given function to the elements of this stream.
            .collect(Collectors.toList());
    assertEquals(asList("A", "B", "HELLO"), collected);
}   

最初の例では特別なことは何もありません。a は大文字のFunctionを返すためStringに適用されます。

を使用する2番目の例flatMap

@Test
public void testflatMap() throws Exception {
    List<Integer> together = Stream.of(asList(1, 2), asList(3, 4)) // Stream of List<Integer>
            .flatMap(List::stream)
            .map(integer -> integer + 1)
            .collect(Collectors.toList());
    assertEquals(asList(2, 3, 4, 5), together);
}

2番目の例では、リストのストリームが渡されます。整数のストリームではありません!
変換関数を(マップを介して)使用する必要がある場合、最初にストリームを別の何か(ストリームの整数)にフラット化する必要があります。
flatMapが削除されると、次のエラーが返されます。演算子+は、引数の型リスト(int)に対して未定義です。
整数のリストに+ 1を適用することはできません!


@PrashanthDebbadwar Stream of Stream<Integer>ではなくStream ofになってしまうと思いますInteger
ペイン

166

明確なアイデアを得るために、投稿を完全に読んでください。

マップとflatMap:

リストから各単語の長さを返すには、以下のようにします。

下記のショートバージョン

以下に示す2つのリストを収集すると

フラットマップなし => [1,2]、[1,1] => [[1,2]、[1,1]]ここでは2つのリストがリスト内に配置されているため、出力はリストを含むリストになります

フラット地図 => [1,2]、[1,1] => [1,2,1,1]ここでは、2つのリストが平坦化され、出力要素のみを含むリストになるようだけ値は、リストに配置されます

基本的には、すべてのオブジェクトを1つにマージします

##詳細なバージョンを以下に示します:-

例:-
リスト["STACK"、 "OOOVVVER"]を考えて、["STACKOVER"]のようなリストを返そうとしている(そのリストから一意の文字のみを返す)最初は、以下のようなことをして、リスト [「STACKOVER」] から [「STACK」、「OOOVVVER」]

public class WordMap {
  public static void main(String[] args) {
    List<String> lst = Arrays.asList("STACK","OOOVER");
    lst.stream().map(w->w.split("")).distinct().collect(Collectors.toList());
  }
}

ここでの問題は、mapメソッドに渡されたLambdaが各単語のString配列を返すため、mapメソッドから返されるストリームは実際にはStream型ですが、文字のストリームを表すにはStreamが必要です。下の画像は、問題。

図A:

ここに画像の説明を入力してください

この問題はflatmapを使用して解決できます。OK、mapArrays.stream
を使用してこれを解決する方法を見てみましょう。 まず、配列のストリームではなく文字のストリームが必要です。たとえば、配列を取得してストリームを生成するArrays.stream()というメソッドがあります。

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
    .map(Arrays::stream).distinct() //Make array in to separate stream
    .collect(Collectors.toList());

ストリームのリスト(より正確には、Stream>)になるため、上記はまだ機能しません。代わりに、最初に各単語を個々の文字の配列に変換してから、各配列を個別のストリームにする必要があります。

flatMapを使用すると、この問題を次のように修正できるはずです。

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
    .flatMap(Arrays::stream).distinct() //flattens each generated stream in to a single stream
    .collect(Collectors.toList());

flatMapは、ストリームではなく、そのストリームのコンテンツを使用して各配列のマッピングを実行します。map(Arrays :: stream)の使用中に生成される個々のストリームはすべて、単一のストリームにマージされます。図Bは、flatMapメソッドを使用した効果を示しています。図Aのマップの機能と比較してください。 図B ここに画像の説明を入力してください

flatMapメソッドを使用すると、ストリームの各値を別のストリームに置き換え、生成されたすべてのストリームを1つのストリームに結合できます。


2
素敵な図解。
Hitesh

107

1行の答え:flatMapaをに平坦化するのCollection<Collection<T>>に役立ちますCollection<T>。同様に、Optional<Optional<T>>into もフラット化しOptional<T>ます。

ここに画像の説明を入力してください

あなたが、見ることができるようにmap()のみ:

  • 中間タイプは Stream<List<Item>>
  • 戻り値の型は List<List<Item>>

flatMap()

  • 中間タイプは Stream<Item>
  • 戻り値の型は List<Item>

これは、すぐ下で使用されているコードのテスト結果です。

-------- Without flatMap() -------------------------------
     collect() returns: [[Laptop, Phone], [Mouse, Keyboard]]

-------- With flatMap() ----------------------------------
     collect() returns: [Laptop, Phone, Mouse, Keyboard]

使用されるコード

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class Parcel {
  String name;
  List<String> items;

  public Parcel(String name, String... items) {
    this.name = name;
    this.items = Arrays.asList(items);
  }

  public List<String> getItems() {
    return items;
  }

  public static void main(String[] args) {
    Parcel amazon = new Parcel("amazon", "Laptop", "Phone");
    Parcel ebay = new Parcel("ebay", "Mouse", "Keyboard");
    List<Parcel> parcels = Arrays.asList(amazon, ebay);

    System.out.println("-------- Without flatMap() ---------------------------");
    List<List<String>> mapReturn = parcels.stream()
      .map(Parcel::getItems)
      .collect(Collectors.toList());
    System.out.println("\t collect() returns: " + mapReturn);

    System.out.println("\n-------- With flatMap() ------------------------------");
    List<String> flatMapReturn = parcels.stream()
      .map(Parcel::getItems)
      .flatMap(Collection::stream)
      .collect(Collectors.toList());
    System.out.println("\t collect() returns: " + flatMapReturn);
  }
}

8
非常に鮮明な例..、例でコンセプトを理解するのに数秒以上かかることはありません...
TechDog

2
いい説明。シンプルで最良の説明に本当に感謝
Sachin Rane

42

渡す関数stream.mapは、1つのオブジェクトを返す必要があります。つまり、入力ストリーム内の各オブジェクトは、出力ストリーム内で1つのオブジェクトになります。

渡す関数stream.flatMapは、各オブジェクトのストリームを返します。つまり、関数は各入力オブジェクトに対してオブジェクトをいくつでも返すことができます(なしを含む)。結果のストリームは、1つの出力ストリームに連結されます。


なぜ「各入力オブジェクトに対して任意の数のオブジェクト(何も含まない)を返す」が必要なのですか?
Derek Mahar、

4
@DerekMaharこれには多くのユースケースがあります。たとえばDepartment、組織内にのストリームがあるとします。各部門には0からn Employee秒の範囲があります。必要なのは、すべての従業員のストリームです。それで、あなたは何をしますか?部署を受け取り、その従業員のストリームを返すflatMapメソッドを記述します。
フィリップ

フィリップ、あなたの例は使用する主な理由を説明していますflatMapか?これは偶発的なものである可能性があり、主要なユースケースやflatMap存在する理由を示していません。(以下に続く...)
Derek Mahar、

dzone.com/articles/understanding-flatmapを読んだ後、背後にある主な動機flatMapは、を使用するときに存在するであろうエラーに対応することだと思いますmap。元のセットの1つ以上のアイテムを出力アイテムにマップできない場合の対処方法を教えてください。各入力オブジェクトに中間セット(OptionalorまたはStream)を導入するflatMapことで、「無効な」入力オブジェクト(または、stackoverflow.com / a / 52248643/107158の精神における「不良リンゴ」と呼ばれる)を最終セット。
デレク・マハール

1
@DerekMaharはい、各入力オブジェクトが出力オブジェクトを返す場合と返さない場合がある状況は、フラットマップのもう1つの優れた使用例です。
フィリップ

29

Mapの場合、要素のリストと(関数、アクション)f soがあります。

[a,b,c] f(x) => [f(a),f(b),f(c)]

また、フラットマップの場合は、要素リストのリストがあり、(function、action)fがあり、結果をフラット化する必要があります。

[[a,b],[c,d,e]] f(x) =>[f(a),f(b),f(c),f(d),f(e)]

25

ここでのほとんどの答えは、単純な問題を複雑にしています。あなたがすでにどのようにmap機能するかを理解しているなら、それはかなり把握しやすいはずです。

を使用すると、不要な入れ子構造になってしまう場合があります。この方法はmap()flatMap()ラッピングを回避することでこれを克服するように設計されています。


例:

1

List<List<Integer>> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .collect(Collectors.toList());

以下を使用することで、リストのネストを回避できますflatMap

List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .flatMap(i -> i.stream())
  .collect(Collectors.toList());

2

Optional<Optional<String>> result = Optional.of(42)
      .map(id -> findById(id));

Optional<String> result = Optional.of(42)
      .flatMap(id -> findById(id));

どこ:

private Optional<String> findById(Integer id)

申し訳ありませんが、ポイント1の2番目のスニペットはの代わりにコンパイルされません List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());。それはあるべきですStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
アーサー

@arthur私はここでVavrのストリームとリストを使用したと思いますが、少し混乱する可能性があることに同意します-これを標準のJavaに変更します
Grzegorz Piwowarek

@GrzegorzPiwowarek この簡単な説明はどうですか?
ユージーン

22

オラクルのオプションに関する記事は、マップとフラットマップのこの違いを強調しています。

String version = computer.map(Computer::getSoundcard)
                  .map(Soundcard::getUSB)
                  .map(USB::getVersion)
                  .orElse("UNKNOWN");

残念ながら、このコードはコンパイルできません。どうして?変数computerの型Optional<Computer>はなので、mapメソッドを呼び出すことは完全に正しいことです。ただし、getSoundcard()はOptionalタイプのオブジェクトを返します。これは、マップ操作の結果がタイプのオブジェクトであることを意味しますOptional<Optional<Soundcard>>。その結果、最も外側のOptionalには別のOptionalが値として含まれているため、getUSB()メソッドはサポートされていないため、getUSB()の呼び出しは無効です。

ストリームの場合、flatMapメソッドは関数を引数として取り、別のストリームを返します。この関数は、ストリームの各要素に適用され、ストリームのストリームになります。ただし、flatMapには、生成された各ストリームをそのストリームのコンテンツで置き換える効果があります。つまり、関数によって生成されるすべての個別のストリームは、1つのストリームに融合または「フラット化」されます。ここで必要なのは似たようなものですが、2レベルのOptionalを1つに「フラット化」します。

オプションは、flatMapメソッドもサポートします。その目的は、(map操作と同様に)Optionalの値に変換関数を適用し、結果の2レベルのOptionalを1つにフラット化することです。

したがって、コードを正しくするために、flatMapを使用して次のように書き直す必要があります。

String version = computer.flatMap(Computer::getSoundcard)
                   .flatMap(Soundcard::getUSB)
                   .map(USB::getVersion)
                   .orElse("UNKNOWN");

最初のflatMapはのOptional<Soundcard>代わりにが返されることを保証しOptional<Optional<Soundcard>>、2番目のflatMapはを返すために同じ目的を達成しOptional<USB>ます。getVersion()はOptionalオブジェクトではなくStringを返すため、3番目の呼び出しはmap()である必要があることに注意してください。

http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html


1
質問はStream.mapとStream.flatMapについてであり、Optional.mapとanfd Optional.flatMapについてではありませんでした
djames

4
しかし、オプションとフラットマップの問題を理解するのに大いに役立ちました。
ロイック

2
@djames、それは完全に有効な答えです。「ストリームでは、flatMapメソッドは関数を引数として受け取ります...」:)
skwisgaar

これは、ここにある他の回答のいくつかに非常に役立つ追加だと思います。
Mz A

また、soundCardがnullの場合、flatMap()バージョンはnullpointerexceptionをスローします。では、オプションの約束された利点はどこにあるのでしょうか?
エカテリーナ

16

私はこれに答えるつもりかどうかは定かではありませんが、これを理解していない誰かに直面するたびに、私は同じ例を使用します。

あなたがリンゴを持っていると想像してください。A mapは、そのリンゴをapple-juice、たとえば、1対1のマッピングに変換しています。

同じリンゴを取り、種子だけを取り出します。flatMapつまり、1対多、1つのリンゴを入力として、多くのシードを出力として使用します。


4
それは興味深い例です:)
cassiomolin

このflatMap場合、すべての袋を1つの袋に注ぐ前に、最初に各リンゴの種子を別々の袋に集めますか?
Derek Mahar、

@DerekMaharは、以前はjava-10の前の1つのバッグに貧弱flatmapでした。つまり、実際には怠惰ではありませんでしたが、java-10以降は怠惰です
Eugene

@Eugeneは、あなたが私にはっきりしない説明しようとしているもう少し怠惰な概念を説明してください。私はderkerMaharがコメントで説明したことはjava10の前に何が起こっていたのか理解しましたか?
JAVA 2019

@JAVAはただ検索しflatMap + lazyます。いくつかの答えがあると思います。
ユージーン

16

map()およびflatMap()

  1. map()

関数はラムダパラメータを取り、Tは要素、RはTを使用して作成された戻り要素を受け取ります。最後に、タイプRのオブジェクトを持つストリームが作成されます。簡単な例は次のとおりです。

Stream
  .of(1,2,3,4,5)
  .map(myInt -> "preFix_"+myInt)
  .forEach(System.out::println);

それは単純にTypeの要素1から5を取りInteger、各要素を使用してString、値"prefix_"+integer_valueを持つタイプから新しい要素を構築し、それを出力します。

  1. flatMap()

flatMap()関数取ることを知っておくと便利ですF<T, R>どこに

  • Tは、Streamをから/で構築できる型です。これは、リスト(T.stream())、配列(Arrays.stream(someArray))など、Streamの元となるフォーム、またはフォームの元となるものであれば何でもかまいません。以下の例では、各開発者には多くの言語があるため、開発者です。言語はリストであり、ラムダパラメータを使用します。

  • Rは、Tを使用して構築される結果のストリームです。Tのインスタンスが多いことを知っていると、当然、Rからのストリームも多くなります。タイプRからのこれらすべてのストリームは、タイプRからの単一の「フラット」ストリームに結合されます。

Bachiri Taoufiqの例は、 ここでの答えがシンプルで理解しやすいと考えています。わかりやすくするために、開発者のチームがあるとします。

dev_team = {dev_1,dev_2,dev_3}

、各開発者は多くの言語を知っています:

dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_2 = {lang_e,lang_f}

適用 Stream.mapを()各DEVの言語を取得するにはdev_teamに:

dev_team.map(dev -> dev.getLanguages())

この構造を与えるでしょう:

{ 
  {lang_a,lang_b,lang_c},
  {lang_d},
  {lang_e,lang_f}
}

これは基本的にList<List<Languages>> /Object[Languages[]]です。それほどきれいではなく、Java8ライクでもありません。

Stream.flatMap()、それは上記の構造とるよう、あなたの事を「フラット化」することができます
し、に変わり、それを{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}基本的に使用することができ、List<Languages>/Language[]/etc...

したがって、最終的には、コードは次のように理解しやすくなります。

dev_team
   .stream()    /* {dev_1,dev_2,dev_3} */
   .map(dev -> dev.getLanguages()) /* {{lang_a,...,lang_c},{lang_d}{lang_e,lang_f}}} */
   .flatMap(languages ->  languages.stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
   .doWhateverWithYourNewStreamHere();

または単に:

dev_team
       .stream()    /* {dev_1,dev_2,dev_3} */
       .flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
       .doWhateverWithYourNewStreamHere();

map()とflatMap()を使用する場合

  • map()ストリームのタイプTの各要素がタイプRの単一の要素にマップ/変換されることになっている場合に使用します。結果は、タイプ(1開始要素-> 1終了要素)とタイプRの要素の新しいストリームのマッピングになります。返されます。

  • flatMap()ストリームからのタイプTの各要素がタイプRの要素のコレクションにマップ/変換されることになっている場合に使用します。結果はタイプ(1開始要素-> n終了要素)のマッピングになります。これらのコレクションは、R型の要素の新しいストリームにマージ(またはフラット化されます。これは、たとえばネストされたループを表す場合に役立ちます

Java 8より前:

List<Foo> myFoos = new ArrayList<Foo>();
    for(Foo foo: myFoos){
        for(Bar bar:  foo.getMyBars()){
            System.out.println(bar.getMyName());
        }
    }

Java 8以降

myFoos
    .stream()
    .flatMap(foo -> foo.getMyBars().stream())
    .forEach(bar -> System.out.println(bar.getMyName()));

11

Map:-このメソッドは、1つの関数を引数として取り、渡された関数をストリームのすべての要素に適用することによって生成された結果で構成される新しいストリームを返します。

想像してみてください、私は整数値のリスト(1,2,3,4,5)と、渡された整数の2乗の論理を持つ1つの関数インターフェイスを持っています。(e-> e * e)。

List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> newList = intList.stream().map( e -> e * e ).collect(Collectors.toList());

System.out.println(newList);

出力:-

[1, 4, 9, 16, 25]

ご覧のとおり、出力は、値が入力ストリームの値の2乗である新しいストリームです。

[1, 2, 3, 4, 5] -> apply e -> e * e -> [ 1*1, 2*2, 3*3, 4*4, 5*5 ] -> [1, 4, 9, 16, 25 ]

http://codedestine.com/java-8-stream-map-method/

FlatMap:-このメソッドは1つの関数を引数として取り、この関数は1つのパラメーターTを入力引数として受け入れ、パラメーターRの1つのストリームを戻り値として返します。この関数がこのストリームの各要素に適用されると、新しい値のストリームが生成されます。各要素によって生成されたこれらの新しいストリームのすべての要素は、このメソッドの戻り値となる新しいストリームにコピーされます。

想像してみてください。学生のオブジェクトのリストがあり、各学生が複数の科目を選択できます。

List<Student> studentList = new ArrayList<Student>();

  studentList.add(new Student("Robert","5st grade", Arrays.asList(new String[]{"history","math","geography"})));
  studentList.add(new Student("Martin","8st grade", Arrays.asList(new String[]{"economics","biology"})));
  studentList.add(new Student("Robert","9st grade", Arrays.asList(new String[]{"science","math"})));

  Set<Student> courses = studentList.stream().flatMap( e -> e.getCourse().stream()).collect(Collectors.toSet());

  System.out.println(courses);

出力:-

[economics, biology, geography, science, history, math]

ご覧のとおり、出力は新しいストリームであり、その値は入力ストリームの各要素によって返されるストリームのすべての要素のコレクションです。

[S1、S2、S3]-> [{"history"、 "math"、 "geography"}、{"economics"、 "biology"}、{"science"、 "math"}]->固有の主題をとる- > [経済学、生物学、地理学、科学、歴史、数学]

http://codedestine.com/java-8-stream-flatmap-method/


ドキュメントリンクを提供するだけでなく、コードを提供する場合、違いが生じる可能性があります
Charles-Antoine Fournel

11

.mapA-> Bマッピング用です

Stream.of("dog", "cat")              // stream of 2 Strings
    .map(s -> s.length())            // stream of 2 Integers: [3, 3]

任意のアイテムAを任意のアイテムに変換しますBJavadoc


.flatMapA-> Stream <B>連結用です

Stream.of("dog", "cat")             // stream of 2 Strings
    .flatMapToInt(s -> s.chars())   // stream of 6 ints:      [d, o, g, c, a, t]

it --1は任意のアイテムAStream< B>に変換し、次に--2はすべてのストリームを1つの(フラット)ストリームに連結します。Javadoc


注1:後者の例は、オブジェクトのストリーム(Stream)ではなく、プリミティブのストリーム(IntStream)にフラット化されていますが、それでもの概念を示してい.flatMapます。

注2:名前にかかわらず、String.chars()メソッドはintを返します。実際の収集がされるように:[100, 111, 103, 99, 97, 116] であり、ここで100のコードである'd'111のコードである'o'等再度、例示の目的のためには、[D、O、G、C、T]として提示されます。


3
ベストアンサー。例を挙げて要点
GabrielBB

1

簡単な答え。

このmap操作ではStreamStream.EXStream<Stream<Integer>>

flatMap操作はStream何かを生成するだけです。EXStream<Integer>


0

また、よく知っている場合は、C#でも同様のことが言えます。基本的に、C#Selectはjava mapおよびC#SelectManyjavaに似ていflatMapます。コレクションのKotlinにも同じことが当てはまります。


0

これは初心者にとって非常に混乱します。基本的な違いはmap、リスト内のエントリごとに1つのアイテムを出力することで、flatMap基本的にはmap+ flatten演算です。より明確にするために、複数の値が必要な場合、たとえばループが配列を返すことが期待される場合は、flatMapを使用してください。この場合、flatMapは非常に役立ちます。

私はこれについてブログを書いています、あなたはここでそれをチェックすることができます



0

操作flatMapをストリーミングしmap、関数を入力として受け入れます。

flatMapは、関数がストリームの各要素に対して新しいストリームを返すことを期待し、各要素に対して関数が返すストリームのすべての要素を組み合わせたストリームを返します。つまり、を使用するとflatMap、ソースの要素ごとに、関数によって複数の要素が作成されます。http://www.zoftino.com/java-stream-examples#flatmap-operation

map関数が変換された値を返すことを期待し、変換された要素を含む新しいストリームを返します。つまり、ではmap、ソースの要素ごとに、変換された要素が関数によって1つ作成されます。 http://www.zoftino.com/java-stream-examples#map-operation


0

flatMap()また、ストリームの部分的な遅延評価を利用します。最初のストリームを読み取り、必要な場合にのみ次のストリームに移動します。動作はここで詳細に説明されています:flatMapは遅延が保証されていますか?


0

map()反復(1レベルのforループ)と考えるflatmap()と、2レベルの反復(入れ子forループのような)です。(各反復要素を入力しfoo、それfoo.getBarList()を繰り返しますbarList


map():ストリームを取得し、すべての要素に対して何かを行い、すべてのプロセスの単一の結果を収集し、別のストリームを出力します。「何かをする」の定義は暗示的です。いずれかの要素の処理の結果がnullnullある場合、最終ストリームを構成するために使用されます。したがって、結果のストリームの要素の数は、入力ストリームの数と等しくなります。

flatmap()要素/ストリームのストリームと関数(明示的な定義)を取り、各ストリームの各要素に関数を適用し、中間ストリームをすべて収集してより大きなストリームにします(「平坦化」)。要素の処理の結果がである場合、null「平坦化」の最終ステップに空のストリームが提供されます。結果のストリームの要素数は、入力が複数のストリームである場合、すべての入力に含まれるすべての要素の合計です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.