In Java 8, qual è la differenza tra i metodi Stream.map()
e Stream.flatMap()
?
Antworten
Zu viele Anzeigen?Der Artikel von Oracle zu Optional hebt diesen Unterschied zwischen map und flatmap hervor:
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
Leider kompiliert dieser Code nicht. Warum? Die Variable computer ist vom Typ
Optional
, daher ist es völlig korrekt, die map-Methode aufzurufen. Jedoch gibt getSoundcard() ein Objekt vom Typ Optional zurück. Das bedeutet, das Ergebnis der map-Operation ist ein Objekt vom TypOptional>
. Als Ergebnis ist der Aufruf von getUSB() ungültig, da das äußerste Optional als Wert ein weiteres Optional enthält, das natürlich die Methode getUSB() nicht unterstützt.Bei Streams nimmt 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. Jedoch hat flatMap den Effekt, jeden generierten Stream durch den Inhalt dieses Streams zu ersetzen. Mit anderen Worten werden alle separaten Streams, die von der Funktion generiert werden, zu einem einzigen Stream zusammengeführt oder "flachgedrückt. Was wir hier wollen, ist etwas Ähnliches, aber wir wollen ein zweistufiges Optional zu einem "flachdrücken".
Optional unterstützt auch eine flatMap-Methode. Ihr Zweck ist es, die Transformationsfunktion auf den Wert eines Optionals anzuwenden (genau wie die map-Operation dies tut) und dann das resultierende zweistufige Optional zu einem einzelnen zu "flachdrücken".
Um also unseren Code korrekt zu machen, müssen wir ihn wie folgt mit flatMap umschreiben:
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
Das erste flatMap stellt sicher, dass ein
Optional
zurückgegeben wird anstatt einesOptional>
, und das zweite flatMap erreicht denselben Zweck, um einOptional
zurückzugeben. Beachten Sie, dass der dritte Aufruf nur ein map() sein muss, da getVersion() einen String und kein Optional-Objekt zurückgibt.
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
Ich bin mir nicht ganz sicher, ob ich darauf antworten soll, aber jedes Mal, wenn ich auf jemanden treffe, der das nicht versteht, benutze ich dasselbe Beispiel.
Stell dir vor, du hast einen Apfel. Ein map
transformiert diesen Apfel zum Beispiel in Apfelsaft
oder eine eins-zu-eins Zuordnung.
Nimm denselben Apfel und hol nur die Kerne heraus, das ist das, was flatMap
macht, oder eine eins zu viele Zuordnung, ein Apfel als Eingabe, viele Kerne als Ausgabe.
Karte:- Diese Methode nimmt eine Funktion als Argument und gibt einen neuen Stream zurück, der aus den Ergebnissen besteht, die durch Anwendung der übergebenen Funktion auf alle Elemente des Streams generiert wurden.
Stellen wir uns vor, ich habe eine Liste von ganzzahligen Werten (1,2,3,4,5) und ein Funktionsschnittstelle, deren Logik das Quadrat der übergebenen Ganzzahl ist. (e -> e * e).
List intList = Arrays.asList(1, 2, 3, 4, 5);
List newList = intList.stream().map(e -> e * e).collect(Collectors.toList());
System.out.println(newList);
Ausgabe:-
[1, 4, 9, 16, 25]
Wie Sie sehen können, ist die Ausgabe ein neuer Stream, dessen Werte das Quadrat der Werte des Eingabestreams sind.
[1, 2, 3, 4, 5] -> e -> e * e anwenden -> [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 nimmt eine Funktion als Argument, diese Funktion akzeptiert ein Parameter T als Eingabeargument und gibt einen Stream des Parameters R als Rückgabewert zurück. Wenn diese Funktion auf jedes Element dieses Streams angewendet wird, erzeugt sie einen Stream neuer Werte. Alle Elemente dieser neuen Streams, die von jedem Element generiert wurden, werden dann in einen neuen Stream kopiert, der der Rückgabewert dieser Methode sein wird.
Stellen wir uns vor, ich habe eine Liste von Studentenobjekten, wobei jeder Student sich für mehrere Fächer entscheiden kann.
List studentList = new ArrayList();
studentList.add(new Student("Robert","5. Klasse", Arrays.asList(new String[]{"Geschichte","Mathematik","Geographie"})));
studentList.add(new Student("Martin","8. Klasse", Arrays.asList(new String[]{"Wirtschaft","Biologie"})));
studentList.add(new Student("Robert","9. Klasse", Arrays.asList(new String[]{"Naturwissenschaft","Mathematik"})));
Set courses = studentList.stream().flatMap(e -> e.getCourse().stream()).collect(Collectors.toSet());
System.out.println(courses);
Ausgabe:-
[Wirtschaft, Biologie, Geographie, Naturwissenschaft, Geschichte, Mathematik]
Wie Sie sehen können, ist die 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"}, {"Wirtschaft","Biologie"}, {"Naturwissenschaft","Mathematik"} ] -> Einmalige Fächer auswählen -> [Wirtschaft, Biologie, Geographie, Naturwissenschaft, Geschichte, Mathematik]
Beim Lesen aller Nachrichten ist der einfache Weg zu verstehen:
- verwenden Sie
map
, wenn Sie eineflache
Liste von Elementen haben: [0, 1, 2, 3, 4, 5] - verwenden Sie
flatMap
, wenn Sie eine Liste von Listen von Elementen haben: [[1, 3, 5], [2, 4, 6]]. Das bedeutet, dass Ihre Liste flach sein muss, bevor die map-Operation auf jedes Element angewendet werden kann
Wenn Sie map()
als eine Iteration (eine Ebene for
-Schleife) betrachten, ist flatmap()
eine Zweiebenen-Iteration (wie eine verschachtelte for
-Schleife). (Geben Sie jedes iterierte Element foo
ein und führen Sie foo.getBarList()
aus und iterieren Sie erneut in dieser barList
)
map()
: Nehmen Sie einen Stream, führen Sie etwas mit jedem Element aus, sammeln Sie das einzelne Ergebnis jedes Prozesses und geben Sie einen anderen Stream aus. Die Definition der "etwas tun Funktion" ist implizit. Wenn die Verarbeitung eines Elements zu null
führt, wird null
verwendet, um den endgültigen Stream zu erstellen. Daher wird die Anzahl der Elemente im resultierenden Stream gleich der Anzahl des Eingabestreams sein.
flatmap()
: Nehmen Sie einen Stream von Elementen/Streams und eine Funktion (explizite Definition), wenden Sie die Funktion auf jedes Element jedes Streams an und sammeln Sie alle Zwischenergebnisse, um einen größeren Stream zu erstellen ("Aufeinanderlegen"). Wenn die Verarbeitung eines Elements zu null
führt, wird ein leerer Stream für den finalen Schritt des "Aufeinanderschichtens" bereitgestellt. Die Anzahl der Elemente im resultierenden Stream entspricht der Anzahl aller beteiligten Elemente in allen Eingaben, wenn die Eingabe mehrere Streams sind.