Dla zupełności, przypadek „kilku zmiennych” jest rzeczywiście możliwy, chociaż wcale nie jest elegancki. Na przykład, dla zmiennych o
, p
oraz q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
Proszę zwrócić uwagę na zastosowanie obsługi orElseGet()
sprawy, że o
, p
i q
nie są zmiennymi, ale wyrażeniami albo drogimi, albo z niepożądanymi skutkami ubocznymi.
W najbardziej ogólnym przypadku coalesce(e[1],e[2],e[3],...,e[N])
coalesce-expression(i) == e[i] when i = N
coalesce-expression(i) == Optional.ofNullable( e[i] ).orElseGet(()-> coalesce-expression(i+1) ) when i < N
Może to generować zbyt długie wyrażenia. Jeśli jednak próbujemy przenieść się do świata bez null
, v[i]
to najprawdopodobniej już jesteśmy typu Optional<String>
, a nie po prostu String
. W tym przypadku,
result= o.orElse(p.orElse(q.get())) ;
lub w przypadku wyrażeń:
result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;
Ponadto, jeśli są również przeprowadzki do stylu funkcjonalnym-deklaratywny, o
, p
, i q
powinny być typu Supplier<String>
jak w:
Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;
A potem całość coalesce
sprowadza się po prostu do o.get()
.
Bardziej konkretny przykład:
Supplier<Integer> hardcodedDefaultAge= ()-> 99 ;
Supplier<Integer> defaultAge= ()-> defaultAgeFromDatabase().orElseGet( hardcodedDefaultAge ) ;
Supplier<Integer> ageInStore= ()-> ageFromDatabase(memberId).orElseGet( defaultAge ) ;
Supplier<Integer> effectiveAge= ()-> ageFromInput().orElseGet( ageInStore ) ;
defaultAgeFromDatabase()
, ageFromDatabase()
i naturalnie ageFromInput()
już wróci Optional<Integer>
.
A potem coalesce
staje się effectiveAge.get()
lub po prostu, effectiveAge
jeśli jesteśmy zadowoleni z Supplier<Integer>
.
IMHO, w Javie 8 zobaczymy coraz więcej kodu o takiej strukturze, ponieważ jest on niezwykle samo-wyjaśniający i jednocześnie wydajny, szczególnie w bardziej złożonych przypadkach.
Tęsknię za klasą, Lazy<T>
która wywołuje Supplier<T>
tylko raz, ale leniwie, a także spójność w definicji Optional<T>
(tj. Optional<T>
- Optional<T>
operatorów, a nawet Supplier<Optional<T>>
).