Was ist in Java 8 der Unterschied zwischen Stream.map()
und Stream.flatMap()
Methoden?
java
java-8
java-stream
Cassiomolin
quelle
quelle
map :: Stream T -> (T -> R) -> Stream R
,flatMap :: Stream T -> (T -> Stream R) -> Stream R
.<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
.map
das Mapper-Lambda von a gibt zurückR
,flatMap
das Mapper-Lambda von a gibt aStream
vonR
(Stream<R>
) zurück. Die vomflatMap
Mapper des Streams zurückgegebenen Streams werden effektiv verkettet. Ansonsten beidesmap
undflatMap
zurückStream<R>
; der Unterschied ist , was die Mapper lambdas zurückkehren,R
gegenStream<R>
.Antworten:
Beide
map
undflatMap
können auf a angewendet werdenStream<T>
und beide geben a zurückStream<R>
. Der Unterschied besteht darin, dass diemap
Operation einen Ausgabewert für jeden Eingabewert erzeugt, während dieflatMap
Operation eine beliebige Anzahl (null oder mehr) für jeden Eingabewert erzeugt.Dies spiegelt sich in den Argumenten für jede Operation wider.
Die
map
Operation nimmt einFunction
, das für jeden Wert im Eingabestream aufgerufen wird, und erzeugt einen Ergebniswert, 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 könnte sich eine API vorstellen, bei der die Mapper-Funktion fürflatMap
einen Wert annimmt und ein Array oder ein Array zurückgibtList
von Werten, die dann an die Ausgabe gesendet werden. Da dies die Stream-Bibliothek ist, besteht eine besonders geeignete Möglichkeit, eine beliebige Anzahl von Rückgabewerten darzustellen, darin, dass die Mapper-Funktion selbst einen Stream zurückgibt! Die vom Mapper zurückgegebenen Werte aus dem Stream werden aus dem Stream abgelassen und an den Ausgabestream übergeben. Die "Klumpen" von Werten, die bei 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
flatMap
zurückgegeben,Stream.empty()
wenn Nullwerte gesendet werden sollen, oder etwa,Stream.of(a, b, c)
wenn mehrere Werte zurückgegeben werden sollen. Aber natürlich kann jeder Stream zurückgegeben werden.quelle
flatMap
Operation genau das Gegenteil von flach. Überlassen Sie es erneut den Informatikern, einen Begriff auf den Kopf zu stellen. Wie eine Funktion, die "transparent" ist, was bedeutet, dass Sie nichts sehen können, was sie tut, nur die Ergebnisse. Wenn Sie umgangssprachlich sagen, dass ein Prozess transparent sein soll, möchten Sie, dass jeder Teil davon gesehen wird.Stream.flatMap
, wie der Name vermuten lässt, ist die Kombination von amap
und einerflat
Operation. Das bedeutet, dass Sie zuerst eine Funktion auf Ihre Elemente anwenden und sie dann reduzieren.Stream.map
Wendet nur eine Funktion auf den Stream an, ohne den Stream zu reduzieren.Um zu verstehen, woraus das Abflachen eines Streams besteht, betrachten Sie eine Struktur
[ [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 ]
.quelle
Ich möchte zwei Beispiele geben , einen bekommen mehr praktischer Sicht:
Erstes Beispiel Herstellung Verwendung von Karte:
Im ersten Beispiel
Function
ist nichts Besonderes. A wird angewendet, um denString
Großbuchstaben zurückzugeben.Zweites Beispiel unter Verwendung von
flatMap
:Im zweiten Beispiel wird ein Listenstrom übergeben. Es ist KEIN Stream von Integer!
Wenn eine Transformationsfunktion verwendet werden muss (über die Karte), muss der Stream zuerst auf etwas anderes reduziert werden (einen Stream of Integer).
Wenn flatMap entfernt wird, wird der folgende Fehler zurückgegeben: Der Operator + ist für die Argumenttypliste (n) undefiniert, int.
Es ist NICHT möglich, + 1 auf eine Liste von Ganzzahlen anzuwenden!
quelle
Stream<Integer>
eher einen Stream von als einen Stream von erhaltenInteger
.Bitte gehen Sie den Beitrag vollständig durch, um eine klare Vorstellung zu bekommen.
map vs flatMap:
Um die Länge jedes Wortes aus einer Liste zurückzugeben, gehen wir wie folgt vor.
Kurzversion unten angegeben
Wenn wir zwei Listen sammeln, die unten angegeben sind
Ohne flache Karte => [1,2], [1,1] => [[1,2], [1,1]] Hier werden zwei Listen in eine Liste eingefügt, sodass die Ausgabe eine Liste mit Listen ist
Mit flacher Karte => [1,2], [1,1] => [1,2,1,1] Hier werden zwei Listen abgeflacht und nur die Werte in die Liste aufgenommen, 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"] zurückzugeben (wobei nur eindeutige Buchstaben aus dieser Liste zurückgegeben werden) liste [“STACKOVER”] aus [“STACK”, ”OOOVVVER”]
Hier ist das Problem, dass Lambda, das an die Map-Methode übergeben wird, 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 brauchen, ist Stream, um einen Stream von Zeichen darzustellen. Das folgende Bild zeigt das Problem.
Abbildung A:
Sie könnten denken, dass wir dieses Problem mithilfe von Flatmap lösen können.
OK, lassen Sie uns sehen, wie Sie dieses Problem mithilfe von map und Arrays.stream lösen können. Zunächst benötigen Sie einen Zeichenstrom anstelle eines Strom von Arrays. Es gibt eine Methode namens Arrays.stream (), die ein Array verwendet und einen Stream erzeugt, zum Beispiel:
Das Obige funktioniert immer noch nicht, da wir jetzt eine Liste von Streams haben (genauer gesagt Stream>). Stattdessen müssen wir zuerst jedes Wort in ein Array einzelner Buchstaben konvertieren und dann jedes Array in einen separaten Stream verwandeln
Mit flatMap sollten wir dieses Problem wie folgt beheben können:
flatMap führt die Zuordnung jedes Arrays nicht zum Stream, sondern zum Inhalt dieses Streams durch. Alle einzelnen Streams, die bei Verwendung von map (Arrays :: stream) generiert werden, werden zu einem einzigen Stream zusammengeführt. Abbildung B zeigt den Effekt der Verwendung der flatMap-Methode. Vergleichen Sie es mit der Karte in Abbildung A. Abbildung B.
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.
quelle
Einzeilige Antwort:
flatMap
Hilft, aCollection<Collection<T>>
in a zu reduzierenCollection<T>
. Auf die gleiche Weise wird auch einOptional<Optional<T>>
in abgeflachtOptional<T>
.Wie Sie sehen können, mit
map()
nur:Stream<List<Item>>
List<List<Item>>
und mit
flatMap()
:Stream<Item>
List<Item>
Dies ist das Testergebnis des unten verwendeten Codes:
Verwendeter Code :
quelle
Die Funktion, an die Sie übergeben,
stream.map
muss ein Objekt zurückgeben. Das bedeutet, dass jedes Objekt im Eingabestream genau ein Objekt im Ausgabestream ergibt.Die Funktion, an die Sie übergeben,
stream.flatMap
gibt für jedes Objekt einen Stream zurück. Das bedeutet, dass die Funktion für jedes Eingabeobjekt eine beliebige Anzahl von Objekten zurückgeben kann (einschließlich keiner). Die resultierenden Streams werden dann zu einem Ausgabestream verkettet.quelle
Department
s in Ihrer Organisation. Jede Abteilung hat zwischen 0 und nsEmployee
. Was Sie brauchen, ist ein Strom aller Mitarbeiter. Also, was machst du? Sie schreiben eine flatMap-Methode, die eine Abteilung übernimmt und einen Strom ihrer Mitarbeiter zurückgibt.flatMap
? Ich vermute, dass es zufällig sein kann und nicht den Hauptanwendungsfall oder den Grund dafür darstelltflatMap
. (Fortsetzung unten ...)flatMap
besteht, Fehler zu berücksichtigen , die bei der Verwendung auftreten würdenmap
. Wie gehen Sie mit Fällen um, in denen ein oder mehrere Elemente im Originalsatz keinem Ausgabeelement zugeordnet werden können? Durch die Einführung eines Zwischensatzes (z. B. einOptional
oderStream
) für jedes EingabeobjektflatMap
können Sie die "ungültigen" Eingabeobjekte (oder die sogenannten "schlechten Äpfel" im Sinne von stackoverflow.com/a/52248643/107158 ) von der ausschließen letzter Satz.Für eine Karte haben wir eine Liste von Elementen und eine (Funktion, Aktion) f so:
und für die flache Karte haben wir eine Liste von Elementen Liste und wir haben ein (Funktion, Aktion) f und wir wollen, dass das Ergebnis abgeflacht wird:
quelle
Ich habe das Gefühl, dass die meisten Antworten hier das einfache Problem überkomplizieren. Wenn Sie bereits verstehen, wie die
map
Werke funktionieren, sollte das ziemlich einfach zu verstehen sein.Es gibt Fälle, in denen bei der Verwendung unerwünschte verschachtelte Strukturen auftreten
map()
können. DieflatMap()
Methode wurde entwickelt, um dies zu vermeiden, indem das Umbrechen vermieden wird.Beispiele:
1
Wir können verschachtelte Listen vermeiden, indem wir Folgendes verwenden
flatMap
:2
wo:
quelle
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());
. Es sollte seinStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
Der Artikel von Oracle über Optional hebt diesen Unterschied zwischen Karte und Flatmap hervor:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
quelle
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. A
map
wandelt diesen Apfelapple-juice
beispielsweise in eine Eins-zu-Eins- Zuordnung um.Nehmen Sie denselben Apfel und holen Sie nur die Samen heraus, das ist es, was
flatMap
tut, oder eins zu viele , ein Apfel als Input, viele Samen als Output.quelle
flatMap
Sammeln Sie für den Fall zuerst die Samen von jedem Apfel in separaten Beuteln, einem Beutel pro Apfel, bevor Sie alle Beutel in einen einzigen Beutel gießen?flatmap
war nicht wirklich faul, aber seit Java-10 ist es faulflatMap + lazy
, ich wette, es wird einige Antworten geben.map () und flatMap ()
map()
Nimmt einfach eine Funktion einen Lambda-Parameter, wobei T das Element und R das mit T erstellte Rückgabeelement ist. Am Ende haben wir einen Stream mit Objekten vom Typ R. Ein einfaches Beispiel kann sein:
Es werden einfach die Elemente 1 bis 5 des Typs verwendet
Integer
, mit jedem Element ein neues Element aus dem TypString
mit Wert erstellt"prefix_"+integer_value
und ausgedruckt.flatMap()
Es ist nützlich zu wissen, dass flatMap () eine Funktion übernimmt,
F<T, R>
bei derT ist ein Typ, aus dem ein Stream erstellt werden kann . Es kann eine Liste (T.stream ()), ein Array (Arrays.stream (someArray)) usw. sein, alles, was ein Stream mit / oder Form sein 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 von Typ R werden jetzt zu einem einzigen "flachen" Stream von Typ R kombiniert .
Beispiel
Die Beispiele von Bachiri Taoufiq , deren Antwort hier zu sehen ist, sind einfach und leicht zu verstehen. Nehmen wir zur Klarheit an, wir haben ein Entwicklerteam:
, wobei jeder Entwickler viele Sprachen beherrscht:
Anwenden von Stream.map () auf dev_team, um die Sprachen der einzelnen Entwickler abzurufen:
gibt Ihnen diese Struktur:
Das ist im Grunde ein
List<List<Languages>> /Object[Languages[]]
. Nicht so sehr hübsch, noch Java8-ähnlich !!mit können
Stream.flatMap()
Sie Dinge "abflachen", während es die obige Struktur nimmtund sie in verwandelt
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, was im Grunde genommen alsList<Languages>/Language[]/etc
...Am Ende wäre Ihr Code also sinnvoller:
oder einfach:
Wann man map () und flatMap () benutzt :
Verwenden Sie diese Option,
map()
wenn jedes Element vom Typ T aus Ihrem Stream einem einzelnen Element vom Typ R zugeordnet / transformiert werden soll . Das Ergebnis ist eine Zuordnung des Typs (1 Startelement -> 1 Endelement) und eines neuen Streams von Elementen des Typs R. ist zurück gekommen.Verwenden Sie diese Option,
flatMap()
wenn jedes Element vom Typ T aus Ihrem Stream einer Sammlung von Elementen vom Typ R zugeordnet / transformiert werden soll . Das Ergebnis ist eine Zuordnung vom Typ (1 Startelement -> n Endelemente) . Diese Sammlungen werden dann zu einem neuen Strom von Elementen vom Typ R zusammengeführt (oder abgeflacht ). Dies ist beispielsweise nützlich, um verschachtelte Schleifen darzustellen .Vor Java 8:
Post Java 8
quelle
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).
Ausgabe:-
Wie Sie sehen können, ist eine Ausgabe ein neuer Stream, dessen Werte ein Quadrat der Werte des Eingabestreams sind.
http://codedestine.com/java-8-stream-map-method/
FlatMap: - Diese Methode verwendet 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.
Stellen wir uns vor, ich habe eine Liste von Schülerobjekten, in denen jeder Schüler sich für mehrere Fächer entscheiden kann.
Ausgabe:-
Wie Sie sehen können, 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"}, {"Wirtschaft", "Biologie"}, {"Wissenschaft", "Mathematik"}] -> nehmen Sie einzigartige Fächer - > [Wirtschaft, Biologie, Geographie, Naturwissenschaften, Geschichte, Mathematik]
http://codedestine.com/java-8-stream-flatmap-method/
quelle
.map ist für A -> B Mapping
Es konvertiert jedes Element
A
in ein beliebiges ElementB
. Javadoc.flatMap ist für A -> Stream <B> Concatinating
es --1 konvertiert jedes Element
A
inStream< B>
, dann --2 verkettet alle Streams zu einem (flachen) Stream. JavadocAnmerkung 1: Obwohl das letztere Beispiel auf einen Strom von Grundelementen (IntStream) anstatt auf einen Strom von Objekten (Stream) beschränkt ist, veranschaulicht es dennoch die Idee des
.flatMap
.Anmerkung 2: Trotz des Namens gibt die String.chars () -Methode Ints zurück. Die eigentliche Sammlung lautet also:
[100, 111, 103, 99, 97, 116]
Wo100
ist der Code von'd'
,111
ist der Code von'o'
usw. Zur Veranschaulichung wird er wiederum als [d, o, g, c, a, t] dargestellt.quelle
Einfache Antwort.
Die
map
Operation kann eineStream
vonStream
.EX erzeugenStream<Stream<Integer>>
flatMap
Betrieb wird nurStream
von etwas produzieren. EXStream<Integer>
quelle
Eine gute Analogie kann auch mit C # sein, wenn Sie damit vertraut sind. Grundsätzlich C #
Select
ähnlich wie Javamap
und C #SelectMany
JavaflatMap
. Gleiches gilt für Kotlin für Sammlungen.quelle
Dies ist für Anfänger sehr verwirrend. Der grundlegende Unterschied besteht darin
map
, dass für jeden Eintrag in der Liste ein Element ausgegeben wird undflatMap
es sich im Grunde um einemap
+flatten
Operation handelt. Um es klarer zu machen, verwenden Sie flatMap, wenn Sie mehr als einen Wert benötigen, z. B. wenn Sie erwarten, dass eine Schleife Arrays zurückgibt, ist flatMap in diesem Fall sehr hilfreich.Ich habe einen Blog darüber geschrieben, den Sie hier nachlesen können .
quelle
Streamen Sie Operationen
flatMap
undmap
akzeptieren Sie 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 Streams kombiniert, die von der Funktion für jedes Element zurückgegeben werden. Mit anderen Worten, mitflatMap
werden für jedes Element aus der Quelle mehrere Elemente von der Funktion erstellt. http://www.zoftino.com/java-stream-examples#flatmap-operationmap
erwartet, dass die Funktion einen transformierten Wert zurückgibt, und gibt einen neuen Stream zurück, der die transformierten Elemente enthält. Mit anderen Worten, mitmap
wird für jedes Element aus der Quelle ein transformiertes Element von der Funktion erstellt. http://www.zoftino.com/java-stream-examples#map-operationquelle
flatMap()
nutzt auch die teilweise träge Auswertung von Streams. Es liest den ersten Stream und geht nur bei Bedarf zum nächsten Stream. Das Verhalten wird hier ausführlich erklärt: Ist flatMap garantiert faul?quelle
Wenn Sie
map()
als Iteration (einstufigefor
Schleife) denken ,flatmap()
handelt es sich um eine zweistufige Iteration (wie eine verschachteltefor
Schleife). (Geben Sie jedes iteratives Elementfoo
, und tuefoo.getBarList()
und iterate, dassbarList
wieder)map()
: Nehmen Sie einen Stream, tun Sie etwas mit jedem Element, sammeln Sie das einzelne Ergebnis jedes Prozesses und geben Sie einen anderen Stream aus. Die Definition von "etwas tun" ist implizit. Wenn die Verarbeitung eines Elements dazu führtnull
,null
wird der endgültige Stream erstellt. Die Anzahl der Elemente im resultierenden Stream entspricht also der Anzahl der Eingabestreams.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 resultierenden Zwischenströme, um einen größeren Stream zu erhalten ("Abflachung"). Wenn die Verarbeitung eines Elements dazu führtnull
, wird ein leerer Stream für den letzten Schritt des "Abflachens" bereitgestellt. Die Anzahl der Elemente im resultierenden Stream ist die Summe aller beteiligten Elemente in allen Eingaben, wenn es sich bei der Eingabe um mehrere Streams handelt.quelle