Was ist der Unterschied zwischen diesen beiden Methoden: Optional.flatMap()
und Optional.map()
?
Ein Beispiel wäre willkommen.
Stream#flatMap
und Optional#flatMap
.
Was ist der Unterschied zwischen diesen beiden Methoden: Optional.flatMap()
und Optional.map()
?
Ein Beispiel wäre willkommen.
Stream#flatMap
und Optional#flatMap
.
Antworten:
Verwenden Sie map
diese Option, wenn die Funktion das benötigte Objekt zurückgibt oder flatMap
wenn die Funktion ein zurückgibt Optional
. Beispielsweise:
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 drucken dasselbe.
[flat]Map
jemals die Mapping-Funktion mit einem aufrufen input == null
? Ich verstehe, dass Optional
Sortcuts, wenn sie nicht vorhanden sind - das [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) scheint dies zu unterstützen - " Wenn ein Wert vorhanden ist, wenden Sie an. . ".
Optional.of(null)
ist ein Exception
. Optional.ofNullable(null) == Optional.empty()
.
Beide übernehmen eine Funktion vom Typ des Optionalen bis zu etwas.
map()
wendet die Funktion " wie sie ist " auf die Option an, die Sie haben:
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>>
!
Darum geht flatMap()
es: Wenn Ihre Funktion bereits eine zurückgibt Optional
, flatMap()
ist sie etwas intelligenter und umschließt sie nicht doppelt, sondern kehrt zurück Optional<U>
.
Es ist die Zusammensetzung zweier funktionaler Redewendungen: map
und flatten
.
Hinweis: - Nachfolgend finden Sie eine Abbildung der Karten- und Flatmap-Funktion. Andernfalls ist Optional in erster Linie für die Verwendung als Rückgabetyp vorgesehen.
Wie Sie vielleicht bereits wissen, ist Optional eine Art Container, der ein einzelnes Objekt enthalten kann oder nicht. Daher kann es überall dort verwendet werden, wo Sie einen Nullwert erwarten (NPE wird möglicherweise nie angezeigt, wenn Optional ordnungsgemäß verwendet wird). Wenn Sie beispielsweise eine Methode haben, die ein Personenobjekt erwartet, das möglicherweise nullwertfähig ist, möchten Sie die Methode möglicherweise wie folgt 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 das Telefon auch optional
class Person{
private Optional<String> phone;
//setter,getter
}
In diesem Fall wird der Aufruf der Map-Funktion den zurückgegebenen Wert in Optional umbrechen und Folgendes ergeben:
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 eine Option auf, ohne sie mit isPresent () zu überprüfen, es sei denn, Sie können nicht ohne NullPointerExceptions leben.
Person
missbraucht Optional
. Es ist gegen die Absicht der API, sie Optional
für Mitglieder wie diese zu verwenden - siehe mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
Was mir geholfen hat, war ein Blick auf den Quellcode der beiden Funktionen.
Map - umschließt das Ergebnis mit einem optionalen Ergebnis.
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
}
}
flatMap - gibt das ' raw' -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
}
}
flatMap
"gibt das 'rohe' Objekt zurück"? flatMap
Gibt auch das zugeordnete Objekt zurück, das in ein "eingeschlossen" ist Optional
. Der Unterschied besteht darin, dass im Fall von flatMap
die Mapper-Funktion das zugeordnete Objekt in das umschließt, Optional
während map
das Objekt selbst eingeschlossen wird Optional
.
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
in eine Option eingewickelt , falls optionalValue
vorhanden, oder eine leere Option , falls nicht vorhanden .
Wenn Sie das Ergebnis, das Sie einfach verwenden können ifPresent()
, nicht verarbeiten müssen, hat es keinen Rückgabewert:
optionalValue.ifPresent(results::add);
Optional.flatMap()
::Funktioniert ähnlich wie bei Streams. Glättet den Strom von Strömen. Mit dem Unterschied, dass der Wert, wenn er angezeigt wird, auf die Funktion angewendet wird. Andernfalls wird ein leeres optionales Element zurückgegeben.
Sie können es zum Erstellen optionaler Wertfunktionsaufrufe verwenden.
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 das inverse()
oder das squareRoot()
zurückgegeben wird Optional.empty()
, ist das Ergebnis leer.
Optional<Double>
Typ als Rückgabetyp hat.
In Ordnung. 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); // ②
}
}
Optional # map gibt wie Stream einen Wert zurück, der von Optional umschlossen wird. Deshalb erhalten wir eine verschachtelte Option - Optional<Optional<Insurance>
. Und bei ② wollen wir es als Versicherungsinstanz abbilden, so geschah die Tragödie. Die Wurzel ist verschachtelte Optionals. Wenn wir den Kernwert unabhängig von den Muscheln 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 Ihnen Java 8 In Action dringend empfohlen , wenn Sie Java8 systematisch lernen möchten.