Was ist der Unterschied zwischen Optional.flatMap und Optional.map?

Lesezeit: 8 Minuten

Benutzer-Avatar
co-abhängig

Was ist der Unterschied zwischen diesen beiden Methoden: Optional.flatMap() und Optional.map()?

Ein Beispiel wäre wünschenswert.

  • Siehe stackoverflow.com/questions/26684562/…

    – Alexis C.

    16. Juni 2015 um 10:14 Uhr

  • @AlexisC. Ihr Link bezieht sich auf die Karte und die FlatMap von Stream, nicht auf Optional.

    – Eran

    16. Juni 2015 um 10:16 Uhr

  • @Eran Das spielt keine Rolle, wenn Sie verstehen, wie map/flatMap funktioniert, ob es sich um einen Stream handelt oder nicht, ist es dasselbe für ein Optional. Wenn der Op verstanden hat, wie es für einen Stream funktioniert, sollte er diese Frage nicht stellen. Das Konzept ist das gleiche.

    – Alexis C.

    16. Juni 2015 um 10:18 Uhr


  • @AlexisC. Nicht wirklich. Die flatMap von Optional hat wenig mit der flatMap von Stream gemeinsam.

    – Eran

    16. Juni 2015 um 10:22 Uhr

  • @Eran Ich spreche über die konzeptionell Unterschied zwischen einer Karte und einer FlatMap mache ich keine Eins-zu-Eins-Korrespondenz zwischen Stream#flatMap und Optional#flatMap.

    – Alexis C.

    16. Juni 2015 um 10:28 Uhr


Benutzer-Avatar
Assyrien

Benutzen map ob die Funktion das benötigte Objekt zurückgibt oder flatMap wenn die Funktion eine zurückgibt Optional. Zum Beispiel:

public static void main(String[] args) {
  Optional<String> s = Optional.of("input");
  System.out.println(s.map(Test::getOutput));
  System.out.println(s.flatMap(Test::getOutputOpt));
}

static String getOutput(String input) {
  return input == null ? null : "output for " + input;
}

static Optional<String> getOutputOpt(String input) {
  return input == null ? Optional.empty() : Optional.of("output for " + input);
}

Beide print-Anweisungen geben dasselbe aus.

  • Frage: würde [flat]Map Rufen Sie die Zuordnungsfunktion jemals mit an auf input == null? Mein Verständnis ist das Optional sortcuts, wenn es nicht vorhanden ist – die [JavaDoc ](docs.oracle.com/javase/8/docs/api/java/util/…) scheint dies zu untermauern – “Wenn ein Wert vorhanden ist, gelten …“.

    – Boris die Spinne

    19. Februar 2016 um 10:24 Uhr

  • @BoristheSpider Optional.of(null) != Optional.empty()

    – Diego Martinoia

    6. Oktober 2016 um 9:36 Uhr

  • @DiegoMartinoia Optional.of(null) ist ein Exception. Optional.ofNullable(null) == Optional.empty().

    – Boris die Spinne

    6. Oktober 2016 um 9:38 Uhr

  • @BoristheSpider ja, du hast recht. Ich habe versucht, auf Ihre Frage zu antworten, aber ich glaube, ich habe es noch unklarer gemacht: konzeptionell sollte Optional.ofNullable(null) NICHT leer sein, aber in der Praxis wird es als so angesehen, und daher werden Map/Flatmap nicht ausgeführt.

    – Diego Martinoia

    6. Oktober 2016 um 9:44 Uhr

  • Ich denke, die Eingabe sollte weder in getOutputOpt noch in getOutput null sein

    – DanyalBurke

    14. März 2017 um 11:47 Uhr

Benutzer-Avatar
Diego Martinoia

Beide übernehmen eine Funktion vom Typ des Optionalen zu etwas.

map() wendet die Funktion “wie es ist” Optional haben Sie:

if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));

Was passiert, wenn Ihre Funktion eine Funktion von ist T -> Optional<U>?
Ihr Ergebnis ist jetzt ein Optional<Optional<U>>!

Das ist, was flatMap() geht es um: wenn Ihre Funktion bereits eine zurückgibt Optional, flatMap() ist ein bisschen schlauer und wickelt es nicht doppelt ein und kehrt zurück Optional<U>.

Es ist die Zusammensetzung von zwei funktionalen Redewendungen: map und flatten.

Okay. Du Sie müssen ‘flatMap’ nur verwenden, wenn Sie mit verschachtelten Optionals konfrontiert sind. Hier ist das Beispiel.

public class Person {

    private Optional<Car> optionalCar;

    public Optional<Car> getOptionalCar() {
        return optionalCar;
    }
}

public class Car {

    private Optional<Insurance> optionalInsurance;

    public Optional<Insurance> getOptionalInsurance() {
        return optionalInsurance;
    }
}

public class Insurance {

    private String name;

    public String getName() {
        return name;
    }

}

public class Test {

    // map cannot deal with nested Optionals
    public Optional<String> getCarInsuranceName(Person person) {
        return person.getOptionalCar()
                .map(Car::getOptionalInsurance) // ① leads to a Optional<Optional<Insurance>
                .map(Insurance::getName);       // ②
    }

}

Wie Stream gibt Optional#map einen Wert zurück, der von einem Optional umschlossen ist. Deshalb bekommen wir ein verschachteltes Optional — Optional<Optional<Insurance>. Und bei ② wollen wir es als Versicherungsinstanz abbilden, so ist die Tragödie passiert. Die Wurzel sind verschachtelte Optionals. Wenn wir den Kernwert unabhängig von den Hüllen erhalten können, werden wir es schaffen. Das macht flatMap.

public Optional<String> getCarInsuranceName(Person person) {
    return person.getOptionalCar()
                 .flatMap(Car::getOptionalInsurance)
                 .map(Insurance::getName);
}

Am Ende habe ich das dringend empfohlen Java 8 in Aktion an Sie, wenn Sie Java8 systematisch lernen möchten.

Benutzer-Avatar
SandeepGodara

Hinweis:- Unten ist die Abbildung der Map- und Flatmap-Funktion, ansonsten ist Optional in erster Linie nur für die Verwendung als Rückgabetyp konzipiert.

Wie Sie vielleicht bereits wissen, ist Optional eine Art Container, der ein einzelnes Objekt enthalten kann oder nicht, sodass es überall dort verwendet werden kann, wo Sie einen Nullwert erwarten (Sie werden NPE möglicherweise nie sehen, wenn Sie Optional richtig verwenden). Wenn Sie beispielsweise eine Methode haben, die ein Personenobjekt erwartet, das nullable sein kann, möchten Sie die Methode vielleicht so schreiben:

void doSome(Optional<Person> person){
  /*and here you want to retrieve some property phone out of person
    you may write something like this:
  */
  Optional<String> phone = person.map((p)->p.getPhone());
  phone.ifPresent((ph)->dial(ph));
}
class Person{
  private String phone;
  //setter, getters
}

Hier haben Sie einen String-Typ zurückgegeben, der automatisch in einen optionalen Typ eingeschlossen wird.

Wenn die Personenklasse so aussah, ist Telefon auch optional

class Person{
  private Optional<String> phone;
  //setter,getter
}

In diesem Fall umschließt der Aufruf der map-Funktion den zurückgegebenen Wert in Optional und ergibt so etwas wie:

Optional<Optional<String>> 
//And you may want Optional<String> instead, here comes flatMap

void doSome(Optional<Person> person){
  Optional<String> phone = person.flatMap((p)->p.getPhone());
  phone.ifPresent((ph)->dial(ph));
}

PS; Rufen Sie niemals die get-Methode (falls erforderlich) für ein Optional auf, ohne es mit isPresent() zu überprüfen, es sei denn, Sie können nicht ohne NullPointerExceptions leben.

Benutzer-Avatar
Robert Niestroj

Was mir geholfen hat, war ein Blick in den Quellcode der beiden Funktionen.

Karte – schließt das Ergebnis in ein Optional ein.

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value)); //<--- wraps in an optional
    }
}

flachKarte – gibt das ‘rohe’ Objekt zurück

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value)); //<---  returns 'raw' object
    }
}

  • Was meinst du mit flatMap “gibt das ‘rohe’ Objekt zurück”? flatMap gibt auch das zugeordnete Objekt “verpackt” in an zurück Optional. Der Unterschied besteht darin, dass im Fall von flatMapumschließt die Mapper-Funktion das zugeordnete Objekt in der Optional während map selbst hüllt das Objekt ein Optional.

    – Derek Mahar

    9. Oktober 2019 um 8:46 Uhr


  • @DerekMahar hat meinen gelöscht, keine Notwendigkeit, ihn erneut zu posten, da Sie Ihren Kommentar richtig bearbeitet haben.

    – maxxime

    10. Oktober 2019 um 12:04 Uhr

  • Optional.map():

Nimmt jedes Element und wenn der Wert existiert, wird er an die Funktion übergeben:

Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);

Jetzt hinzugefügt hat einen von drei Werten: true oder false eingewickelt in ein Optional Wenn optionalValue anwesend war, oder ein leer Optional ansonsten.

Wenn Sie das Ergebnis nicht verarbeiten müssen, können Sie es einfach verwenden ifPresent()es hat keinen Rückgabewert:

optionalValue.ifPresent(results::add); 
  • Optional.flatMap():

Funktioniert ähnlich wie die gleiche Methode von Streams. Flacht den Stream von Streams ab. Mit dem Unterschied, dass, wenn der Wert präsentiert wird, er auf Funktion angewendet wird. Andernfalls wird eine leere Option zurückgegeben.

Sie können es verwenden, um Funktionsaufrufe mit optionalen Werten zu erstellen.

Angenommen, wir haben Methoden:

public static Optional<Double> inverse(Double x) {
    return x == 0 ? Optional.empty() : Optional.of(1 / x);
}

public static Optional<Double> squareRoot(Double x) {
    return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
}

Dann können Sie die Quadratwurzel der Inversen berechnen, wie:

Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);

oder, wenn Sie es vorziehen:

Optional<Double> result = Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);

Wenn entweder die inverse() oder der squareRoot() kehrt zurück Optional.empty()das Ergebnis ist leer.

  • Was meinst du mit flatMap “gibt das ‘rohe’ Objekt zurück”? flatMap gibt auch das zugeordnete Objekt “verpackt” in an zurück Optional. Der Unterschied besteht darin, dass im Fall von flatMapumschließt die Mapper-Funktion das zugeordnete Objekt in der Optional während map selbst hüllt das Objekt ein Optional.

    – Derek Mahar

    9. Oktober 2019 um 8:46 Uhr


  • @DerekMahar hat meinen gelöscht, keine Notwendigkeit, ihn erneut zu posten, da Sie Ihren Kommentar richtig bearbeitet haben.

    – maxxime

    10. Oktober 2019 um 12:04 Uhr

Benutzer-Avatar
Matthias Stephan

Sie können sich auf den folgenden Link beziehen, um es im Detail zu verstehen (beste Erklärung, die ich finden konnte):

https://www.programmergirl.com/java-8-map-flatmap-difference/

Sowohl map als auch flatMap – Accept Function. Der Rückgabetyp von map() ist ein einzelner Wert, während flatMap einen Strom von Werten zurückgibt

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

  • In Ihren Methodensignaturen sind beide Rückgabetypen Streams? Ich dachte, dass flatMap würde einfach verschachtelte optional auspacken? Können Sie näher erläutern, wie sich dies auf Streams bezieht?

    – Yu Chen

    15. Januar um 21:37 Uhr

1014490cookie-checkWas ist der Unterschied zwischen Optional.flatMap und Optional.map?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy