it-swarm.com.de

Was ist der Unterschied zwischen map- und flatMap-Methoden in Java 8?

Was ist in Java 8 der Unterschied zwischen Stream.map und Stream.flatMap ?

589
cassiomolin

Beide map und flatMap können auf einen Stream<T> angewendet werden, und beide geben einen Stream<R> zurück. Der Unterschied besteht darin, dass die map -Operation einen Ausgabewert für jeden Eingabewert erzeugt, während die flatMap -Operation eine beliebige Anzahl (null oder mehr) von Werten für jeden Eingabewert erzeugt.

Dies spiegelt sich in den Argumenten für jede Operation wider.

Die map -Operation nimmt eine Function auf, die für jeden Wert im Eingabestream aufgerufen wird und einen Ergebniswert erzeugt, der an den Ausgabestream gesendet wird.

Die flatMap -Operation übernimmt eine Funktion, die konzeptionell einen Wert verbrauchen und eine beliebige Anzahl von Werten erzeugen möchte. In Java ist es jedoch umständlich, wenn eine Methode eine beliebige Anzahl von Werten zurückgibt, da Methoden nur null oder einen Wert zurückgeben können. Man kann sich eine API vorstellen, bei der die Mapper-Funktion für flatMap einen Wert annimmt und ein Array oder eine List von Werten zurückgibt, die dann an die Ausgabe gesendet werden. Da dies die Streams-Bibliothek ist, kann die Mapper-Funktion selbst einen Stream zurückgeben, um eine beliebige Anzahl von Rückgabewerten darzustellen. Die vom Mapper zurückgegebenen Werte aus dem Stream werden aus dem Stream abgelassen und an den Ausgabestream übergeben. Die "Werteklumpen", die von jedem Aufruf der Mapper-Funktion zurückgegeben werden, werden im Ausgabestream überhaupt nicht unterschieden, daher wird die Ausgabe als "abgeflacht" bezeichnet.

Typischerweise wird die Mapper-Funktion von flatMap verwendet, um Stream.empty() zurückzugeben, wenn Nullwerte gesendet werden sollen, oder so etwas wie Stream.of(a, b, c), wenn mehrere Werte zurückgegeben werden sollen. Aber natürlich kann jeder Stream zurückgegeben werden.

709
Stuart Marks

Stream.flatMap ist, wie der Name vermuten lässt, die Kombination einer map und einer flat -Operation. Das heißt, Sie wenden zuerst eine Funktion auf Ihre Elemente an und reduzieren sie dann. Stream.map wendet nur eine Funktion auf den Stream an, ohne den Stream zu reduzieren.

Um zu verstehen, worin Abflachen ein Stream besteht, betrachten Sie eine Struktur wie [ [1,2,3],[4,5,6],[7,8,9] ] mit "zwei Ebenen". Abflachen bedeutet, es in eine "einstufige" Struktur umzuwandeln: [ 1,2,3,4,5,6,7,8,9 ].

354
Dici

Ich möchte 2 Beispiele nennen, um eine mehr praktische Sichtweise zu erhalten:
Erstes Beispiel unter Verwendung der Karte:

@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);
}   

Nichts Besonderes im ersten Beispiel: Es wird Function angewendet, um String in Großbuchstaben zurückzugeben.

Zweites Beispiel unter Verwendung von 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);
}

Im zweiten Beispiel wird ein Stream of List übergeben. Es ist KEIN Stream von Integer!
Wenn eine Transformationsfunktion (über eine Karte) verwendet werden muss, muss der Stream zuerst auf etwas anderes reduziert werden (einen Stream mit einer ganzen Zahl).
Wenn flatMap entfernt wird, wird der folgende Fehler zurückgegeben: Der Operator + ist für die Argumenttypen Liste, int. undefiniert
Es ist NICHT möglich, + 1 auf eine Liste von ganzen Zahlen anzuwenden!

210
Rudy Vissers

Bitte gehen Sie den Beitrag vollständig durch, um eine klare Vorstellung zu bekommen.

map vs flatMap:

Um eine Länge jedes Wortes aus einer Liste zurückzugeben, würden wir wie folgt vorgehen.

Kurze Version weiter unten

Wenn wir zwei Listen sammeln, die unten angegeben sind

Ohne flache Karte => [1,2], [1,1] => [[1,2], [1,1]] Hier werden zwei Listen innerhalb einer Liste platziert, sodass die Ausgabe eine Liste mit Listen ist

Mit flat map => [1,2], [1,1] => [1,2,1,1] Hier werden zwei Listen abgeflacht und nur die Werte in der Liste platziert, sodass die Ausgabe eine Liste ist, die nur Elemente enthält

Grundsätzlich werden alle Objekte zu einem zusammengeführt

## Detaillierte Version wurde unten angegeben: -

Zum Beispiel: -
Betrachten Sie eine Liste ["STACK", "OOOVVVER"] und wir versuchen, eine Liste wie [“STACKOVER”] (nur eindeutige Buchstaben aus dieser Liste zurückgeben) Zunächst würden wir wie folgt vorgehen, um eine Liste [“STACKOVER”] zurückzugeben ”] von [“ 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());
  }
}

Hier besteht das Problem darin, dass Lambda, das an die map-Methode übergeben wurde, für jedes Wort ein String-Array zurückgibt. Der von der map-Methode zurückgegebene Stream ist also tatsächlich vom Typ Stream. Was wir jedoch benötigen, ist Stream, um einen Zeichenstrom darzustellen Problem.

Abbildung A:

enter image description here

Sie könnten denken, dass wir dieses Problem mit flatmap lösen können,
OK, lassen Sie uns sehen, wie dies mit map und Arrays.stream gelöst werden kann brauchen einen Strom von Zeichen anstelle eines Stroms von Arrays. Es gibt eine Methode namens Arrays.stream (), die ein Array aufnimmt und einen Stream erzeugt, zum Beispiel:

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());

Das Obige funktioniert immer noch nicht, da wir nun eine Liste von Streams haben (genauer gesagt Stream>). Stattdessen müssen wir zuerst jedes Wort in ein Array von einzelnen Buchstaben konvertieren und dann jedes Array in einen separaten Stream umwandeln

Mit flatMap sollten wir dieses Problem wie folgt beheben können:

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 würde jedes Array nicht mit Stream, sondern mit dem Inhalt dieses Streams abbilden. Alle einzelnen Streams, die bei der Verwendung von map (Arrays :: stream) generiert würden, werden zu einem einzigen Stream zusammengeführt. Abbildung B zeigt die Auswirkungen der Verwendung der flatMap-Methode. Vergleichen Sie es mit dem, was die Karte in Abbildung A bewirkt. Abbildung B enter image description here

Mit der flatMap-Methode können Sie jeden Wert eines Streams durch einen anderen Stream ersetzen und dann alle generierten Streams zu einem einzigen Stream zusammenfügen.

134
TechDog

Einzeilige Antwort: flatMap hilft, einen _Collection<Collection<T>>_ in einen _Collection<T>_ zu reduzieren. Auf die gleiche Weise wird auch ein Optional<Optional<T>> zu Optional<T>.

enter image description here

Wie Sie sehen können, ist mit map() nur Folgendes möglich:

  • Der Zwischentyp ist _Stream<List<Item>>_
  • Der Rückgabetyp ist _List<List<Item>>_

und mit flatMap():

  • Der Zwischentyp ist _Stream<Item>_
  • Der Rückgabetyp ist _List<Item>_

Dies ist das Testergebnis aus dem unten verwendeten Code:

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

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

Verwendeter Code :

_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);
  }
}
_
75
nxhoaf

Die Funktion, die Sie an stream.map übergeben, muss ein Objekt zurückgeben. Das bedeutet, dass jedes Objekt im Eingabestream genau ein Objekt im Ausgabestream ergibt.

Die Funktion, die Sie an stream.flatMap übergeben, gibt für jedes Objekt einen Stream zurück. Dies bedeutet, dass die Funktion für jedes Eingabeobjekt eine beliebige Anzahl von Objekten zurückgeben kann (auch keine). Die resultierenden Ströme werden dann zu einem Ausgangsstrom verkettet.

38
Philipp

für eine Map haben wir eine Liste von Elementen und eine (Funktion, Aktion) f so:

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

und für die flache Karte haben wir eine Liste mit Elementen und wir haben eine (Funktion, Aktion) f und wir wollen, dass das Ergebnis abgeflacht wird:

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

Ich habe das Gefühl, dass die meisten Antworten hier das einfache Problem überkomplizieren. Wenn Sie bereits verstehen, wie map funktioniert, sollte dies ziemlich einfach zu verstehen sein.

Es gibt Fälle, in denen es bei Verwendung von map() zu unerwünschten verschachtelten Strukturen kommen kann. Mit der flatMap() -Methode soll dies überwunden werden, indem Umbruch vermieden wird.


Beispiele:

1

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

Wir können es vermeiden, verschachtelte Listen zu haben, indem wir flatMap verwenden:

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));

wo:

private Optional<String> findById(Integer id)
24

Der Artikel von Oracle zu Optional hebt diesen Unterschied zwischen Map und Flatmap hervor:

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

Leider lässt sich dieser Code nicht kompilieren. Warum? Der variable Computer ist vom Typ Optional<Computer>, daher ist es vollkommen korrekt, die Kartenmethode aufzurufen. GetSoundcard () gibt jedoch ein Objekt vom Typ Optional zurück. Dies bedeutet, dass das Ergebnis der Kartenoperation ein Objekt vom Typ Optional<Optional<Soundcard>> ist. Infolgedessen ist der Aufruf von getUSB () ungültig, da das äußerste optionale Element ein anderes optionales Element als Wert enthält, das die Methode getUSB () natürlich nicht unterstützt.

Bei Streams übernimmt die flatMap-Methode eine Funktion als Argument, die einen anderen Stream zurückgibt. Diese Funktion wird auf jedes Element eines Streams angewendet, was zu einem Stream von Streams führen würde. FlatMap ersetzt jedoch jeden generierten Stream durch den Inhalt dieses Streams. Mit anderen Worten, alle separaten Streams, die von der Funktion generiert werden, werden zu einem einzigen Stream zusammengefasst oder "abgeflacht". Was wir hier wollen, ist etwas Ähnliches, aber wir wollen ein zweistufiges Optional in ein "abflachen".

Optional unterstützt auch eine flatMap-Methode. Der Zweck besteht darin, die Transformationsfunktion auf den Wert eines optionalen Elements anzuwenden (genau wie bei der Map-Operation) und dann das resultierende zweistufige optionale Element in ein einzelnes Element zu reduzieren.

Um unseren Code zu korrigieren, müssen wir ihn mit flatMap wie folgt umschreiben:

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

Die erste flatMap stellt sicher, dass ein Optional<Soundcard> anstelle eines Optional<Optional<Soundcard>> zurückgegeben wird, und die zweite flatMap erfüllt denselben Zweck, um einen Optional<USB> zurückzugeben. Beachten Sie, dass der dritte Aufruf nur map () sein muss, da getVersion () einen String und kein optionales Objekt zurückgibt.

http://www.Oracle.com/technetwork/articles/Java/java8-optional-2175753.html

19
Rusty Core

Ich bin mir nicht sicher, ob ich darauf antworten soll, aber jedes Mal, wenn ich jemandem gegenüberstehe, der dies nicht versteht, verwende ich dasselbe Beispiel.

Stellen Sie sich vor, Sie haben einen Apfel. Ein map transformiert dieses Apple in Apple-juice oder eine Eins-zu-Eins Zuordnung.

Nehmen Sie das gleiche Apple und holen Sie nur die Samen heraus, das ist, was flatMap tut, oder ein eins zu viele, ein Apple als Input, viele Samen als Output.

13
Eugene

Map: - Diese Methode verwendet eine Funktion als Argument und gibt einen neuen Stream zurück, der aus den Ergebnissen besteht, die durch Anwenden der übergebenen Funktion auf alle Elemente des Streams generiert wurden.

Stellen wir uns vor, ich habe eine Liste von Ganzzahlwerten (1,2,3,4,5) und eine Funktionsschnittstelle, deren Logik das Quadrat der übergebenen Ganzzahl ist. (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);

ausgabe:-

[1, 4, 9, 16, 25]

Wie Sie sehen, ist eine Ausgabe ein neuer Stream, dessen Werte ein Quadrat der Werte des Eingabestreams sind.

[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: - Diese Methode akzeptiert eine Funktion als Argument, diese Funktion akzeptiert einen Parameter T als Eingabeargument und gibt einen Strom von Parameter R als Rückgabewert zurück. Wenn diese Funktion auf jedes Element dieses Streams angewendet wird, wird ein Stream mit neuen Werten erstellt. Alle Elemente dieser neuen Streams, die von jedem Element generiert werden, werden dann in einen neuen Stream kopiert, der ein Rückgabewert dieser Methode ist.

Lassen Sie uns ein Bild machen, ich habe eine Liste von Studentenobjekten, in denen sich jeder Student für mehrere Fächer entscheiden kann.

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);

ausgabe:-

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

Wie Sie sehen, ist eine Ausgabe ein neuer Stream, dessen Werte eine Sammlung aller Elemente der Streams sind, die von jedem Element des Eingabestreams zurückgegeben werden.

[S1, S2, S3] -> [{"Geschichte", "Mathematik", "Geographie"}, {"Ökonomie", "Biologie"}, {"Wissenschaft", "Mathematik"}] -> eindeutige Fächer nehmen - > [Wirtschaft, Biologie, Geographie, Naturwissenschaften, Geschichte, Mathematik]

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

11
lalitbhagtani

map () und flatMap ()

  1. map()

Nimmt einfach eine Funktion, einen Lambda-Parameter, wobei T das Element ist und R das Rückgabeelement, das mit T erstellt wurde. Am Ende haben wir einen Stream mit Objekten vom Typ R. Ein einfaches Beispiel kann sein:

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

Es werden einfach die Elemente 1 bis 5 vom Typ Integer verwendet, um aus jedem Element ein neues Element vom Typ String mit dem Wert "prefix_"+integer_value zu erstellen und es auszudrucken.

  1. flatMap()

Es ist nützlich zu wissen, dass flapMap () eine Funktion F<T, R> hat

  • T ist ein Typ aus , aus dem/mit ein Stream erstellt werden kann. Es kann sich um eine Liste (T.stream ()), ein Array (Arrays.stream (someArray)) usw. handeln, alles, woraus ein Stream bestehen kann. Im folgenden Beispiel hat jeder Entwickler viele Sprachen, also Entwickler. Languages ​​ist eine Liste und verwendet einen Lambda-Parameter.

  • R ist der resultierende Stream, der mit T erstellt wird. Da wir wissen, dass wir viele Instanzen von T haben, werden wir natürlich viele Streams von R haben. Alle diese Streams vom Typ R werden nun zu kombiniert ein einzelner 'flacher' Stream vom Typ R.

Beispiel

Die Beispiele von Bachiri Taoufiq siehe die Antwort hier sind einfach und leicht zu verstehen. Nehmen wir aus Gründen der Übersichtlichkeit an, wir haben ein Entwicklerteam:

dev_team = {dev_1,dev_2,dev_3}

, wobei jeder Entwickler viele Sprachen beherrscht:

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

Anwenden von Stream.map () auf dev_team, um die Sprachen der einzelnen Entwickler zu erhalten:

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

wird Ihnen diese Struktur geben:

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

das ist im Grunde ein List<List<Languages>> /Object[Languages[]]. Nicht so sehr hübsch, noch Java8-like !!

mit Stream.flatMap() können Sie Dinge "abflachen", wenn sie die obige Struktur annehmen
und verwandelt es in {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}, das im Grunde genommen als List<Languages>/Language[]/ect ... verwendet werden kann.

am Ende würde Ihr Code also mehr Sinn machen:

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();

oder einfach:

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

Wann benutzt man map () und flatMap () :

  • Verwenden Sie map(), wenn jedes Element des Typs T aus Ihrem Stream in ein einzelnes Element des Typs R abgebildet/transformiert werden soll. Das Ergebnis ist eine Zuordnung des Typs (1 Startelement -> 1 Endelement) und neuer Strom von Elementen vom Typ R wird zurückgegeben.

  • Verwenden Sie flatMap(), wenn jedes Element des Typs T aus Ihrem Stream einer Sammlung von Elementen des Typs R zugeordnet/transformiert werden soll. Das Ergebnis ist eine Zuordnung des Typs (1 Startelement -> n Endelemente) . Diese Sammlungen werden dann zusammengeführt (oder abgeflacht ) zu einem neuen Datenstrom von Elementen des Typs R. Dies ist beispielsweise zur Darstellung nützlich verschachtelte Schleifen .

Vor Java 8:

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

Beitrag Java 8

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

Dies ist für Anfänger sehr verwirrend. Der grundlegende Unterschied ist, dass map für jeden Eintrag in der Liste einen Eintrag ausgibt und flatMap im Grunde eine map + flatten -Operation ist. Um es klarer zu machen, verwenden Sie flatMap, wenn Sie mehr als einen Wert benötigen. Wenn Sie beispielsweise erwarten, dass eine Schleife Arrays zurückgibt, ist flatMap in diesem Fall sehr hilfreich.

Ich habe einen Blog darüber geschrieben, den könnt ihr euch ansehen hier .

1
Niraj Chauhan

Einfache Antwort.

Die map -Operation kann eine Stream von Stream erzeugen. EX Stream<Stream<Integer>>

flatMap Der Vorgang erzeugt nur Stream von etwas. EX Stream<Integer>

1
Melad Basilius

Auch eine gute Analogie kann mit C # sein, wenn Sie sich damit auskennen. Grundsätzlich ähnelt C # Select Java map und C # SelectMany Java flatMap. Gleiches gilt für Kotlin für Sammlungen.

1
Arsenius

Stream-Operationen flatMap und map akzeptieren eine Funktion als Eingabe.

flatMap erwartet, dass die Funktion für jedes Element des Streams einen neuen Stream zurückgibt, und gibt einen Stream zurück, der alle Elemente der von der Funktion für jedes Element zurückgegebenen Streams kombiniert. Mit anderen Worten, mit flatMap werden für jedes Element aus der Quelle mehrere Elemente von der Funktion erstellt. http://www.zoftino.com/Java-stream-examples#flatmap-operation

map erwartet, dass die Funktion einen transformierten Wert zurückgibt und einen neuen Stream mit den transformierten Elementen zurückgibt. Mit anderen Worten, mit map wird für jedes Element aus der Quelle ein transformiertes Element von der Funktion erstellt. http://www.zoftino.com/Java-stream-examples#map-operation

0
Arnav Rao

flatMap() nutzt auch die teilweise verzögerte Auswertung von Streams. Der erste Stream wird gelesen und nur bei Bedarf wird zum nächsten Stream gewechselt. Das Verhalten wird hier ausführlich erklärt: Ist flatMap garantiert faul?

0
S.K.