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

1052voto

Stuart Marks Punkte 119555

Sowohl map als auch flatMap können auf einem Stream angewendet werden und sie geben beide einen Stream zurück. Der Unterschied besteht darin, dass die map-Operation für jeden Eingabewert einen Ausgabewert erzeugt, während die flatMap-Operation eine beliebige Anzahl (null oder mehr) Werte für jeden Eingabewert erzeugt.

Dies spiegelt sich in den Argumenten jeder Operation wider.

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

Die flatMap-Operation nimmt eine Funktion entgegen, die konzeptionell einen Wert konsumieren möchte und eine beliebige Anzahl von Werten produzieren möchte. In Java ist es jedoch umständlich, dass 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ür flatMap einen Wert entgegennimmt und ein Array oder eine List von Werten zurückgibt, die dann an den Ausgang gesendet werden. Da es sich hier um die Streams-Bibliothek handelt, ist eine besonders passende Möglichkeit, eine beliebige Anzahl von Rückgabewerten darzustellen, dass die Mapper-Funktion selbst einen Stream zurückgibt! Die Werte aus dem vom Mapper zurückgegebenen Stream werden aus dem Stream entnommen und an den Ausgabestream weitergeleitet. Die "Klumpen" von Werten, die jeder Aufruf der Mapper-Funktion zurückgibt, werden im Ausgabestream überhaupt nicht unterschieden, daher wird gesagt, dass der Ausgang "flach gemacht" wurde.

Typischerweise gibt die Mapper-Funktion von flatMap Stream.empty() zurück, wenn sie null Werte senden möchte, oder etwas wie Stream.of(a, b, c), wenn sie mehrere Werte zurückgeben möchte. Aber natürlich kann jeder Stream zurückgegeben werden.

836voto

Dici Punkte 24522

Stream.flatMap, wie es sich bereits aus seinem Namen ableiten lässt, ist die Kombination einer map und einer flat Operation. Das bedeutet, dass Sie zunächst eine Funktion auf Ihre Elemente anwenden und sie dann zusammenführen. Stream.map wendet nur eine Funktion auf den Stream an, ohne den Stream zusammenzuführen.

Um zu verstehen, was das "Zusammenführen" eines Streams bedeutet, nehmen Sie eine Struktur wie [ [1,2,3],[4,5,6],[7,8,9] ], die "zwei Ebenen" hat. Diese zu vereinen heißt, sie in eine "eine Ebene" Struktur zu transformieren: [ 1,2,3,4,5,6,7,8,9 ].

322voto

Rudy Vissers Punkte 4881

Ich würde gerne 2 Beispiele geben, um einen praktischeren Standpunkt zu bekommen:
Erstes Beispiel mit Verwendung von map:

@Test
public void convertStringToUpperCaseStreams() {
    List collected = Stream.of("a", "b", "hello") // Stream aus String 
            .map(String::toUpperCase) // Gibt einen Stream zurück, der aus den Ergebnissen besteht, die durch Anwendung der gegebenen Funktion auf die Elemente dieses Streams erzeugt werden.
            .collect(Collectors.toList());
    assertEquals(asList("A", "B", "HELLO"), collected);
}

Im ersten Beispiel ist nichts Besonderes, eine Function wird angewendet, um den String in Großbuchstaben zurückzugeben.

Zweites Beispiel mit Verwendung von flatMap:

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

Im zweiten Beispiel wird ein Stream von Listen übergeben. Es ist KEIN Stream von Integer!
Wenn eine Transformationsfunktion verwendet werden muss (über map), muss der Stream zunächst zu etwas anderem (ein Stream von Integer) abgeflacht werden.
Wenn flatMap entfernt wird, wird der folgende Fehler zurückgegeben: Der Operator + ist für die Argumenttypen List, int nicht definiert.
Es ist NICHT möglich, + 1 auf eine List von Integern anzuwenden!

209voto

TechDog Punkte 2940

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

Karte vs flatMap:

Um die Länge jedes Wortes aus einer Liste zurückzugeben, würden wir etwas Ähnliches tun wie unten..

Kurzversion unten gegeben

Wenn wir zwei Listen sammeln, unten angegeben

Ohne flatmap => [1,2],[1,1] => [[1,2],[1,1]] Hier werden zwei Listen in einer Liste platziert, daher wird die Ausgabe eine Liste enthaltend Listen sein

Mit flat map => [1,2],[1,1] => [1,2,1,1] Hier werden zwei Listen abgeflacht und nur die Werte werden in der Liste platziert, daher wird die Ausgabe eine Liste enthaltend nur Elemente sein

Grundsätzlich vereint es alle Objekte zu einem einzigen

## Ausführliche Version wurde unten gegeben:-

Zum Beispiel:-
Betrachten Sie eine Liste [“STACK”, ”OOOVVVER”] und wir versuchen eine Liste wie [“STACKOVER”] zurückzugeben (nur eindeutige Buchstaben aus dieser Liste zurückgeben) Anfangs würden wir etwas Ähnliches tun, um eine Liste [“STACKOVER”] von [“STACK”, ”OOOVVVER”] zurückzugeben

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

Hier liegt das Problem darin, dass die Lambda, die dem map-Methoden übergeben wird, für jedes Wort eine Zeichenfolgenarray zurückgibt, daher ist der von der map-Methode zurückgegebene Stream tatsächlich vom Typ Stream, aber was wir benötigen, ist Stream, um einen Strom von Zeichen zu repräsentieren, das folgende Bild verdeutlicht das Problem.

Figur A:

Bildbeschreibung eingeben

Sie könnten denken, dass wir dieses Problem mit flatmap lösen können,
OK, schauen wir, wie wir dies mit map und Arrays.stream lösen können Zunächst benötigen Sie einen Strom von Zeichen anstelle eines Stroms von Arrays. Es gibt eine Methode namens Arrays.stream(), die ein Array akzeptiert und einen Stream erzeugt, zum Beispiel:

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Wort in Array von Buchstaben umwandeln
    .map(Arrays::stream).distinct() //Array in separaten Strom umwandeln
    .collect(Collectors.toList());

Das funktioniert immer noch nicht, denn jetzt landen wir bei einer Liste von Strömen (genauer gesagt, Stream>), stattdessen müssen wir zuerst jedes Wort in ein Array von einzelnen Buchstaben umwandeln und dann jedes Array in einen separaten Strom umwandeln

Indem wir flatMap verwenden, sollten wir dieses Problem wie folgt lösen können:

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Wort in Array von Buchstaben umwandeln
    .flatMap(Arrays::stream).distinct() //jeden generierten Strom in einen einzigen Strom abflachen
    .collect(Collectors.toList());

flatMap würde jedes Array nicht mit einem Strom, sondern mit den Inhalten dieses Stroms abbilden. Alle einzelnen Ströme, die während der Verwendung von map(Arrays::stream) generiert werden, werden zu einem einzelnen Strom zusammengeführt. Abbildung B veranschaulicht die Auswirkungen der Verwendung der flatMap-Methode. Vergleichen Sie dies mit dem, was map in Abbildung A tut. Figur B Bildbeschreibung eingeben

Die flatMap-Methode ermöglicht es Ihnen, jeden Wert eines Stroms durch einen anderen Strom zu ersetzen und dann alle generierten Ströme in einen einzigen Strom zusammenzuführen.

160voto

Hoa Nguyen Punkte 11962

Eine Zeile Antwort: flatMap hilft dabei, eine Collection> in eine Collection zu flatten. Auf die gleiche Weise wird es auch ein Optional> in ein Optional flatten.

geben Sie hier eine Bildbeschreibung ein

Wie Sie sehen können, nur mit map():

  • Der Zwischentyp ist Stream>
  • Der Rückgabetyp ist List>

und mit flatMap():

  • Der Zwischentyp ist Stream
  • Der Rückgabetyp ist List

Dies ist das Testergebnis des direkt darunter verwendeten Codes:

-------- Ohne flatMap() -------------------------------
     collect() gibt zurück: [[Laptop, Phone], [Mouse, Keyboard]]

-------- Mit flatMap() ----------------------------------
     collect() gibt zurück: [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 items;

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

  public List getItems() {
    return items;
  }

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

    System.out.println("-------- Ohne flatMap() ---------------------------");
    List> mapReturn = parcels.stream()
      .map(Parcel::getItems)
      .collect(Collectors.toList());
    System.out.println("\t collect() gibt zurück: " + mapReturn);

    System.out.println("\n-------- Mit flatMap() ------------------------------");
    List flatMapReturn = parcels.stream()
      .map(Parcel::getItems)
      .flatMap(Collection::stream)
      .collect(Collectors.toList());
    System.out.println("\t collect() gibt zurück: " + flatMapReturn);
  }
}

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