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

60voto

epox Punkte 6406

.map ist für A -> B Mapping

Stream.of("dog", "cat")              // Stream von 2 Strings
    .map(s -> s.length())            // Stream von 2 Integers: [3, 3]

es wandelt jedes Element A in jedes Element B um. Javadoc


.flatMap ist für A -> Stream< B> Konkatenierung

Stream.of("dog", "cat")             // Stream von 2 Strings
    .flatMapToInt(s -> s.chars())   // Stream von 6 ints:      [d, o, g, c, a, t]

es --1 wandelt jedes Element A in Stream< B> um und dann --2 konkateniert alle Streams zu einem (flachen) Stream. Javadoc


Hinweis 1: Obwohl das letzte Beispiel zu einem Stream von Primitiven (IntStream) anstelle eines Streams von Objekten (Stream) führt, veranschaulicht es dennoch die Idee des .flatMap.

Hinweis 2: Trotz des Namens gibt die Methode String.chars() ints zurück. Daher wird die tatsächliche Sammlung sein: [100, 111, 103, 99, 97, 116] , wobei 100 der Code für 'd' ist, 111 der Code für 'o' usw. Auch hier wird zur Veranschaulichung [d, o, g, c, a, t] präsentiert.

55voto

Philipp Punkte 64222

Die Funktion, die Sie an stream.map übergeben, muss ein Objekt zurückgeben. Das bedeutet, dass jedes Objekt im Eingabestrom genau einem Objekt im Ausgabestrom entspricht.

Die Funktion, die Sie an stream.flatMap übergeben, gibt für jedes Objekt einen Strom zurück. Das bedeutet, dass die Funktion für jedes Eingabeobjekt beliebig viele Objekte zurückgeben kann (einschließlich keines). Die resultierenden Ströme werden dann zu einem Ausgabestrom konkateniert.

39voto

Für eine Karte 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 von Elementen und wir haben eine (Funktion, Aktion) f und möchten, dass das Ergebnis abgeflacht wird :

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

32voto

Grzegorz Piwowarek Punkte 12514

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

Es gibt Fälle, in denen wir unerwünschte verschachtelte Strukturen bekommen können, wenn wir map() verwenden. Die Methode flatMap() wurde entwickelt, um dies zu überwinden, indem sie das Einwickeln vermeidet.


Beispiele:

1

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

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

List result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .flatMap(i -> i.stream())
  .collect(Collectors.toList());

2

Optional> result = Optional.of(42)
      .map(id -> findById(id));

Optional result = Optional.of(42)
      .flatMap(id -> findById(id));

wo:

private Optional findById(Integer id)

32voto

arthur Punkte 3117

map() und flatMap()

  1. map()

Nimmt einfach eine Funktion als Lambda-Parameter, wobei T das Element und R das zurückgegebene Element ist, das mit T erstellt wird. Am Ende haben wir einen Stream mit Objekten vom Typ R. Ein einfaches Beispiel könnte sein:

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

Es nimmt einfach Elemente 1 bis 5 des Typs Integer, verwendet jedes Element, um ein neues Element vom Typ String mit dem Wert "prefix_"+integer_wert zu erstellen und gibt es aus.

  1. flatMap()

Es ist nützlich zu wissen, dass flatMap() eine Funktion F annimmt, wobei

  • T ein Typ ist, von dem aus ein Stream erstellt werden kann. Es kann eine Liste (T.stream()), ein Array (Arrays.stream(someArray)), etc. sein.. alles, von dem aus ein Stream erstellt werden kann. Im unten stehenden Beispiel hat jeder Entwickler viele Sprachen, also ist dev. Languages eine Liste und wird einen Lambda-Parameter verwenden.

  • R ist der resultierende Stream, der mit T erstellt wird. Da wir viele Instanzen von T haben, werden wir natürlich viele Streams von R haben. Alle diese Streams vom Typ R werden jetzt zu einem einzigen 'flachen' Stream vom Typ R kombiniert.

Beispiel

Die Beispiele von Bachiri Taoufiq [siehe seine Antwort hier] 1 sind einfach und leicht zu verstehen. Nur zur Klarstellung, nehmen wir an, wir haben ein Team von Entwicklern:

dev_team = {dev_1,dev_2,dev_3}

, wobei jeder Entwickler viele Sprachen kennt:

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

Mit Stream.map() auf dev_team angewendet, um die Sprachen jedes Entwicklers zu erhalten:

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

erhalten Sie diese Struktur:

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

was im Grunde eine List> /Object[Sprachen[]] ist. Nicht sehr hübsch, noch Java8-like!!

mit Stream.flatMap() können Sie alles 'abflachen', da es die obige Struktur nimmt
und sie in {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f} umwandelt, was im Grunde als List/Sprache[]/etc verwendet werden kann...

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

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

oder einfach:

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

Wann map() und flatMap() verwenden:

  • Verwenden Sie map(), wenn jedes Element vom Typ T aus Ihrem Stream auf ein einzelnens Element vom Typ R abgebildet/umgewandelt werden soll. Das Ergebnis ist ein Mapping vom Typ (1 Startelement -> 1 Endelement) und es wird ein neuer Stream von Elementen vom Typ R zurückgegeben.

  • Verwenden Sie flatMap(), wenn jedes Element vom Typ T aus Ihrem Stream auf eine Sammlung von Elementen vom Typ R abgebildet/umgewandelt werden soll. Das Ergebnis ist ein Mapping vom Typ (1 Startelement -> n Endelemente). Diese Sammlungen werden dann zusammengeführt (oder abgeflacht) zu einem neuen Stream von Elementen vom Typ R. Dies ist nützlich, um z.B. verschachtelte Schleifen darzustellen.

Vor Java 8:

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

Nach Java 8

meineFoos
    .stream()
    .flatMap(foo -> foo.getMyBars().stream())
    .forEach(bar -> System.out.println(bar.getMyName()));

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