979 Stimmen

Was ist der Unterschied zwischen den Methoden map() und flatMap() in Java 8?

In Java 8, qual è la differenza tra i metodi Stream.map() e Stream.flatMap()?

25voto

Rusty Core Punkte 797

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 Typ Optional>. 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 eines Optional>, und das zweite flatMap erreicht denselben Zweck, um ein Optional 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

19voto

Eugene Punkte 109680

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.

14voto

lalitbhagtani Punkte 449

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]

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

12voto

Harry Coder Punkte 1580

Beim Lesen aller Nachrichten ist der einfache Weg zu verstehen:

  • verwenden Sie map, wenn Sie eine flache 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

8voto

WesternGun Punkte 9127

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X