@AlexisC. Twój link dotyczy mapy strumienia i płaskiej mapy, a nie opcjonalnej.
Eran
1
@Eran To nie ma znaczenia, jeśli rozumiesz, jak działa map / flatMap, niezależnie od tego, czy jest to strumień, czy nie, to jest to samo dla elementu opcjonalnego. Jeśli operator zrozumiał, jak to działa w przypadku Strumienia, nie powinien zadawać tego pytania. Koncepcja jest taka sama.
Alexis C.
2
@AlexisC. Nie całkiem. FlatMap Optional ma niewiele wspólnego z flatMap Stream.
Eran
1
@Eran Mówię o różnicy koncepcyjnej między mapą a płaską mapą, nie tworzę korespondencji jeden do jednego między Stream#flatMapi Optional#flatMap.
Alexis C.
Odpowiedzi:
166
Użyj, mapjeśli funkcja zwraca potrzebny obiekt lub flatMapjeśli funkcja zwraca Optional. Na przykład:
publicstaticvoid main(String[] args){Optional<String> s =Optional.of("input");System.out.println(s.map(Test::getOutput));System.out.println(s.flatMap(Test::getOutputOpt));}staticString getOutput(String input){return input ==null?null:"output for "+ input;}staticOptional<String> getOutputOpt(String input){return input ==null?Optional.empty():Optional.of("output for "+ input);}
Pytanie: czy [flat]Mapkiedykolwiek wywołałby funkcję mapowania z input == null? Rozumiem, że Optionalskróty sortowania, jeśli ich nie ma - [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) wydaje się potwierdzać to - „ Jeśli wartość jest obecna, zastosuj .. . ”.
@BoristheSpider tak, masz rację. Próbowałem odpowiedzieć na twoje pytanie, ale myślę, że uczyniłem to jeszcze bardziej niejasnym: koncepcyjnie, Opcjonalnie.ofNullable (null) NIE powinno być puste, ale w praktyce jest uważane za takie, dlatego mapa / mapa nie jest wykonywana.
Diego Martinoia
1
Myślę, że wejście nie powinno być puste albo getOutputOpt lub getOutput
DanyalBurke
55
Obaj przejmują funkcję od typu opcjonalnego do czegoś.
map()stosuje funkcję „ tak jak jest ” do posiadanej opcji:
Co się stanie, jeśli twoja funkcja jest funkcją z T -> Optional<U>?
Twój wynik to teraz Optional<Optional<U>>!
O to flatMap()właśnie chodzi: jeśli twoja funkcja już zwraca an Optional, flatMap()jest trochę mądrzejsza i nie zawija go podwójnie, zwraca Optional<U>.
To kompozycja dwóch funkcjonalnych idiomów: mapi flatten.
Uwaga: - poniżej znajduje się ilustracja mapy i funkcji mapy płaskiej, w przeciwnym razie Opcjonalne jest przeznaczone głównie do użytku wyłącznie jako typ zwracany.
Jak już być może wiesz, Optional to rodzaj kontenera, który może zawierać pojedynczy obiekt lub nie, więc może być używany wszędzie tam, gdzie spodziewasz się wartości null (możesz nigdy nie zobaczyć NPE, jeśli użyjesz opcji Optional prawidłowo). Na przykład, jeśli masz metodę, która oczekuje obiektu osoby, który może mieć wartość null, możesz napisać metodę mniej więcej tak:
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));}classPerson{privateString phone;//setter, getters}
Tutaj zwróciłeś typ String, który jest automatycznie zawijany w typ opcjonalny.
Jeśli klasa osoby wyglądała tak, to znaczy telefon jest również opcjonalny
W tym przypadku wywołanie funkcji map spowoduje zawinięcie zwróconej wartości w Optional i da coś takiego:
Optional<Optional<String>>//And you may want Optional<String> instead, here comes flatMapvoid doSome(Optional<Person> person){Optional<String> phone = person.flatMap((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));}
PS; Nigdy nie wywołuj metody get (jeśli musisz) na Optional bez sprawdzania jej za pomocą isPresent (), chyba że nie możesz żyć bez NullPointerExceptions.
Myślę, że ten przykład może odwrócić uwagę od natury twojej odpowiedzi, ponieważ twoja klasa Personjest nadużywana Optional. Używanie API Optionalna takich członkach jest wbrew intencjom API - patrz mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/ ...
8bitjunkie
@ 8bitjunkie Dzięki za zwrócenie uwagi, różni się od opcji Scali ..
SandeepGodara
6
Pomogło mi przyjrzenie się kodowi źródłowemu obu funkcji.
Mapa - zawija wynik w opcjonalny.
public<U>Optional<U> map(Function<?super T,?extends U> mapper){Objects.requireNonNull(mapper);if(!isPresent())return empty();else{returnOptional.ofNullable(mapper.apply(value));//<--- wraps in an optional}}
Co masz na myśli, mówiąc flatMap„zwraca„ surowy ”obiekt”? flatMapzwraca również mapowany obiekt „opakowany” w plik Optional. Różnica polega na tym, że w przypadku flatMapfunkcji mapper opakowuje mapowany obiekt, Optionalpodczas gdy mapsama zawija obiekt Optional.
Derek Mahar
@DerekMahar usunął mój, nie musisz go ponownie publikować, ponieważ poprawnie zredagowałeś swój komentarz.
maxxyme
3
Optional.map():
Pobiera każdy element i jeśli wartość istnieje, jest przekazywana do funkcji:
Teraz dodane ma jedną z trzech wartości: truelub falsezawinięte w opcjonalne , jeśli optionalValuebyło obecne, lub puste opcjonalne, w przeciwnym razie.
Jeśli nie musisz przetwarzać wyniku, którego możesz po prostu użyć ifPresent(), nie ma on wartości zwracanej:
optionalValue.ifPresent(results::add);
Optional.flatMap():
Działa podobnie do tej samej metody strumieni. Spłaszcza strumień strumieni. Z tą różnicą, że jeśli wartość jest prezentowana, jest stosowana do funkcji. W przeciwnym razie zwracany jest pusty element opcjonalny.
Możesz go użyć do tworzenia opcjonalnych wywołań funkcji wartości.
Załóżmy, że mamy metody:
publicstaticOptional<Double> inverse(Double x){return x ==0?Optional.empty():Optional.of(1/ x);}publicstaticOptional<Double> squareRoot(Double x){return x <0?Optional.empty():Optional.of(Math.sqrt(x));}
Następnie możesz obliczyć pierwiastek kwadratowy z odwrotności, na przykład:
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
lub jeśli wolisz:
Optional<Double> result =Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);
Jeśli zwraca inverse()lub , wynik jest pusty.squareRoot()Optional.empty()
To się nie kompiluje. Oba twoje wyrażenia zwracają opcjonalne <Double>, a nie Double, do którego przypisujesz wynik.
JL_SO,
@JL_SO masz rację. Ponieważ inverse ma Optional<Double>typ jako typ zwracany.
nazar_art
3
W porządku. Musisz używać „flatMap” tylko wtedy, gdy masz do czynienia z zagnieżdżonymi opcjami . Oto przykład.
publicclassPerson{privateOptional<Car> optionalCar;publicOptional<Car> getOptionalCar(){return optionalCar;}}publicclassCar{privateOptional<Insurance> optionalInsurance;publicOptional<Insurance> getOptionalInsurance(){return optionalInsurance;}}publicclassInsurance{privateString name;publicString getName(){return name;}}publicclassTest{// map cannot deal with nested OptionalspublicOptional<String> getCarInsuranceName(Person person){return person.getOptionalCar().map(Car::getOptionalInsurance)// ① leads to a Optional<Optional<Insurance>.map(Insurance::getName);// ②}}
Podobnie jak w przypadku Stream, opcjonalna # map zwróci wartość opakowaną przez opcjonalny. Dlatego otrzymujemy zagnieżdżony plik Optional - Optional<Optional<Insurance>. W ② chcemy odwzorować to jako instancję ubezpieczeniową, tak właśnie doszło do tragedii. Katalog główny jest zagnieżdżony Optionals. Jeśli uda nam się uzyskać podstawową wartość niezależnie od powłok, zrobimy to. To właśnie robi flatMap.
Stream#flatMap
iOptional#flatMap
.Odpowiedzi:
Użyj,
map
jeśli funkcja zwraca potrzebny obiekt lubflatMap
jeśli funkcja zwracaOptional
. Na przykład:Obie instrukcje print drukują to samo.
źródło
[flat]Map
kiedykolwiek wywołałby funkcję mapowania zinput == null
? Rozumiem, żeOptional
skróty sortowania, jeśli ich nie ma - [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) wydaje się potwierdzać to - „ Jeśli wartość jest obecna, zastosuj .. . ”.Optional.of(null)
jestException
.Optional.ofNullable(null) == Optional.empty()
.Obaj przejmują funkcję od typu opcjonalnego do czegoś.
map()
stosuje funkcję „ tak jak jest ” do posiadanej opcji:Co się stanie, jeśli twoja funkcja jest funkcją z
T -> Optional<U>
?Twój wynik to teraz
Optional<Optional<U>>
!O to
flatMap()
właśnie chodzi: jeśli twoja funkcja już zwraca anOptional
,flatMap()
jest trochę mądrzejsza i nie zawija go podwójnie, zwracaOptional<U>
.To kompozycja dwóch funkcjonalnych idiomów:
map
iflatten
.źródło
Uwaga: - poniżej znajduje się ilustracja mapy i funkcji mapy płaskiej, w przeciwnym razie Opcjonalne jest przeznaczone głównie do użytku wyłącznie jako typ zwracany.
Jak już być może wiesz, Optional to rodzaj kontenera, który może zawierać pojedynczy obiekt lub nie, więc może być używany wszędzie tam, gdzie spodziewasz się wartości null (możesz nigdy nie zobaczyć NPE, jeśli użyjesz opcji Optional prawidłowo). Na przykład, jeśli masz metodę, która oczekuje obiektu osoby, który może mieć wartość null, możesz napisać metodę mniej więcej tak:
Tutaj zwróciłeś typ String, który jest automatycznie zawijany w typ opcjonalny.
Jeśli klasa osoby wyglądała tak, to znaczy telefon jest również opcjonalny
W tym przypadku wywołanie funkcji map spowoduje zawinięcie zwróconej wartości w Optional i da coś takiego:
PS; Nigdy nie wywołuj metody get (jeśli musisz) na Optional bez sprawdzania jej za pomocą isPresent (), chyba że nie możesz żyć bez NullPointerExceptions.
źródło
Person
jest nadużywanaOptional
. Używanie APIOptional
na takich członkach jest wbrew intencjom API - patrz mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/ ...Pomogło mi przyjrzenie się kodowi źródłowemu obu funkcji.
Mapa - zawija wynik w opcjonalny.
flatMap - zwraca obiekt „surowy”
źródło
flatMap
„zwraca„ surowy ”obiekt”?flatMap
zwraca również mapowany obiekt „opakowany” w plikOptional
. Różnica polega na tym, że w przypadkuflatMap
funkcji mapper opakowuje mapowany obiekt,Optional
podczas gdymap
sama zawija obiektOptional
.Optional.map()
:Pobiera każdy element i jeśli wartość istnieje, jest przekazywana do funkcji:
Teraz dodane ma jedną z trzech wartości:
true
lubfalse
zawinięte w opcjonalne , jeślioptionalValue
było obecne, lub puste opcjonalne, w przeciwnym razie.Jeśli nie musisz przetwarzać wyniku, którego możesz po prostu użyć
ifPresent()
, nie ma on wartości zwracanej:Optional.flatMap()
:Działa podobnie do tej samej metody strumieni. Spłaszcza strumień strumieni. Z tą różnicą, że jeśli wartość jest prezentowana, jest stosowana do funkcji. W przeciwnym razie zwracany jest pusty element opcjonalny.
Możesz go użyć do tworzenia opcjonalnych wywołań funkcji wartości.
Załóżmy, że mamy metody:
Następnie możesz obliczyć pierwiastek kwadratowy z odwrotności, na przykład:
lub jeśli wolisz:
Jeśli zwraca
inverse()
lub , wynik jest pusty.squareRoot()
Optional.empty()
źródło
Optional<Double>
typ jako typ zwracany.W porządku. Musisz używać „flatMap” tylko wtedy, gdy masz do czynienia z zagnieżdżonymi opcjami . Oto przykład.
Podobnie jak w przypadku Stream, opcjonalna # map zwróci wartość opakowaną przez opcjonalny. Dlatego otrzymujemy zagnieżdżony plik Optional -
Optional<Optional<Insurance>
. W ② chcemy odwzorować to jako instancję ubezpieczeniową, tak właśnie doszło do tragedii. Katalog główny jest zagnieżdżony Optionals. Jeśli uda nam się uzyskać podstawową wartość niezależnie od powłok, zrobimy to. To właśnie robi flatMap.W końcu zdecydowanie poleciłem ci Java 8 w działaniu , jeśli chcesz systematycznie uczyć się Java8.
źródło