Próbuję zrozumieć różnicę między metodami Optional<T>.orElse()
a Optional<T>.orElseGet()
.
Opis orElse()
metody to „Zwróć wartość, jeśli jest obecna, w przeciwnym razie zwróć inną”.
Chociaż opis orElseGet()
metody brzmi „Zwróć wartość, jeśli jest obecna, w przeciwnym razie wywołaj inną i zwróć wynik tego wywołania”.
orElseGet()
Metoda zajmuje interfejs funkcjonalny dostawca, który zasadniczo nie bierze żadnych parametrów i powrót T
.
W jakiej sytuacji musiałbyś użyć orElseGet()
? Jeśli masz metodę, T myDefault()
dlaczego optional.orElse(myDefault())
raczej tego nie zrobiłbyś optional.orElseGet(() -> myDefault())
?
Nie wydaje się, żeby orElseGet()
opóźniało wykonanie wyrażenia lambda na jakiś czas czy coś, więc po co to ma sens? (Myślałbym, że byłoby bardziej użyteczne, gdyby zwrócił bezpieczniejszego, Optional<T>
którego get()
nigdy nie rzuca a NoSuchElementException
i isPresent()
zawsze zwraca prawdę ... ale oczywiście nie jest, po prostu zwraca T
jak orElse()
).
Czy brakuje mi innej różnicy?
orElseGet
go używasz , dzwoni do dostawcy tylko w przypadku braku wartości.orElse()
tejmyDefault()
metody jest nadal nazywa, ale jego wartość jest nie tylko zwrot używany.orElseGet()
może spowodować poważne błędy: medium.com/alphadev-Odpowiedzi:
Weź te dwa scenariusze:
Jeśli
opt
nie zawiera wartości, oba są rzeczywiście równoważne. Ale jeśliopt
nie zawierają wartości, ileFoo
obiekty będą tworzone?Ps: oczywiście w tym przykładzie różnica prawdopodobnie nie byłaby mierzalna, ale jeśli musisz uzyskać domyślną wartość np. Ze zdalnej usługi internetowej lub z bazy danych, nagle staje się ona bardzo ważna.
źródło
Foo
obiektu, podczas gdy w pierwszym przypadku go utworzy, ale nie użyje go, jeśli wewnątrz jest wartośćOptional
.System.out.println()
to nie kalkulacja ale oświadczenie wytwarzania zaobserwować efekt uboczny. Powiedziałem już, że obserwowane skutki uboczne będą utrudniać optymalizację (strumień wyjściowy konsoli jest zasobem zewnętrznym).Krótka odpowiedź:
Optional.isPresent()
wartościOptional.isPresent() == false
W prawdziwym kodzie warto rozważyć drugie podejście, gdy uzyskanie wymaganego zasobu jest drogie .
Aby uzyskać więcej informacji, rozważ następujący przykład z tą funkcją:
Różnica jest następująca:
Kiedy
optional.isPresent() == false
nie ma różnicy między dwoma sposobami. Jednak kiedyoptional.isPresent() == true
,orElse()
zawsze wywołuje następną funkcję, czy tego chcesz, czy nie.Wreszcie zastosowany przypadek testowy jest następujący:
Wynik:
Kod:
źródło
Optional.isPresent() == false
zamiast tego (fałszywy, nieprawdziwy)Optional.orElse
których stanówIf a value is present, returns the value, otherwise returns other
mogą sugerować takie zachowanie ...orElse()
zachowuje się podobnie dofinally
wtry-catch
wypowiedzi. Mam rację?Sięgnąłem tutaj po problem, o którym wspomniał Kudo .
Dzielę się moim doświadczeniem z innymi.
orElse
luborElseGet
takie jest pytanie:odciski
orElse
ocenia wartość B () niezależnie od wartości opcjonalnej. Jest więcorElseGet
leniwy.źródło
B()
do metody o nazwieorElse()
lubabc()
nie robi to żadnej różnicy,B()
zostanie oceniony.or
deweloperzy błędnego prefiksu (w tym ja, kiedy poprosiłem problemu) do myślenia, że jest to operacja zwarcie, ponieważ to, co jesteśmy przyzwyczajeni w logicznych warunków. Jednak tak nie jest, to tylko nazwa metody, która maor
w swoim prefiksie, więc jej argumenty zostaną ocenione, niezależnie od tego, czyOptional
ma wartość, czy nie. Szkoda, że nazewnictwo jest mylące, nie dlatego, że nic na to nie poradzimy.Powiedziałbym, że największa różnica między
orElse
iorElseGet
pojawia się, gdy chcemy coś ocenić, aby uzyskać nową wartość w tymelse
stanie.Rozważ ten prosty przykład -
Teraz przekształcmy powyższy przykład na użycie
Optional
wraz zorElse
,Teraz przekształcmy powyższy przykład na użycie
Optional
wraz zorElseGet
,Po
orElse
wywołaniuapicall().value
jest on oceniany i przekazywany do metody. Natomiast w przypadkuorElseGet
oceny dzieje się tylko wtedy, gdyoldValue
jest pusta.orElseGet
umożliwia leniwą ocenę.źródło
Poniższy przykład powinien wykazać różnicę:
Odpowiedź pojawia się również w dokumentach.
public T orElseGet(Supplier<? extends T> other)
:Nie
Supplier
będą wywoływane, jeśliOptional
prezenty. natomiast,public T orElse(T other)
:Jeśli
other
metoda zwraca łańcuch, zostanie on wywołany, ale jego wartość nie zostanie zwrócona, jeśliOptional
istnieje.źródło
Różnica jest dość subtelna i jeśli nie zwrócisz na to większej uwagi, będziesz używać jej w niewłaściwy sposób.
Najlepszym sposobem na zrozumienie różnicy między
orElse()
iorElseGet()
jest to, żeorElse()
zawsze będzie wykonane, jeśli wartośćOptional<T>
jest zerowa, czy nie , aleorElseGet()
zostanie wykonana tylko, gdy wartośćOptional<T>
będzie zerowa .Słownikowe znaczenie orElse to : - wykonaj część, gdy czegoś nie ma, ale tutaj jest to sprzeczne, patrz poniższy przykład:
Benchmarki :
Mam nadzieję, że rozwiąże to wątpliwości ludzi takich jak ja, którzy chcą bardzo podstawowego przykładu z ziemi :)
źródło
Przede wszystkim sprawdź deklarację obu metod.
1) OrElse: Wykonaj logikę i przekaż wynik jako argument.
2) OrElseGet: Wykonaj logikę, jeśli wartość wewnątrz opcjonalnego jest pusta
Kilka wyjaśnień na temat powyższej deklaracji: Argument „Optional.orElse” zawsze jest wykonywany niezależnie od wartości obiektu w postaci opcjonalnej (null, pusta lub z wartością). Podczas korzystania z „Optional.orElse” zawsze miej na uwadze powyższy punkt, w przeciwnym razie użycie „Optional.orElse” może być bardzo ryzykowne w następującej sytuacji.
Ryzyko-1) Problem z logowaniem: Jeśli zawartość wewnątrz orElse zawiera jakieś oświadczenie dziennika: W takim przypadku będziesz go logować za każdym razem.
Ryzyko-2) Problem z wydajnością: jeśli zawartość wewnątrz orElse jest czasochłonna: treściochłonne mogą być dowolne operacje we / wy wywołanie DB, wywołanie API, odczyt pliku. Jeśli umieścimy taką treść w orElse (), system ostatecznie wykona kod bezużyteczny.
Ryzyko 3) Nielegalny stan lub błąd: jeśli zawartość wewnątrz orElse mutuje jakiś stan obiektu: Być może używamy tego samego obiektu w innym miejscu, powiedzmy w funkcji Optional.map i może to spowodować błąd krytyczny.
Zatem, kiedy możemy przejść z orElse ()? Preferuj użycie orElse, gdy wartością domyślną jest jakiś stały obiekt, wyliczanie. We wszystkich powyższych przypadkach możemy korzystać z Optional.orElseGet () (który działa tylko wtedy, gdy Optional zawiera niepustą wartość) zamiast Optional.orElse (). Czemu?? W orElse przekazujemy domyślną wartość wyniku, ale w orElseGet przekazujemy Dostawcę, a metoda Dostawcy jest wykonywana tylko wtedy, gdy wartość w Opcjonalnym jest równa null.
Najważniejsze rzeczy z tego:
Wyjaśniłem to w punkcie-2 ( „Optional.map/Optional.orElse”! = „If / else” ) mój średni blog. Używaj Java8 jako programisty, a nie kodera
źródło
Biorąc pod uwagę następujący kod:
jeśli uda nam
value
się w ten sposób:Optional.<String>ofNullable(null)
nie ma żadnej różnicy między orElseGet () i OrElse (), ale jeśli uda namvalue
się w ten sposób:Optional.<String>ofNullable("test")
,orelesMethod()
worElseGet()
nie zostanie wywołana, ale worElse()
nim będzie nazwaneźródło