Solo per completezza, il caso "diverse variabili" è davvero possibile, sebbene non sia affatto elegante. Ad esempio, per le variabili o
, p
e q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
Si prega di notare l'uso del orElseGet()
caso che o
, p
e q
non sono variabili ma espressioni o costose o con effetti collaterali indesiderati.
Nel caso più generale 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
Questo può generare espressioni eccessivamente lunghe. Tuttavia, se stiamo cercando di spostarci in un mondo senza null
, allora v[i]
molto probabilmente sono già di tipo Optional<String>
, al contrario di semplicemente String
. In questo caso,
result= o.orElse(p.orElse(q.get())) ;
o nel caso di espressioni:
result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;
Inoltre, se siete anche muovendo per uno stile funzionale-dichiarativa, o
, p
, e q
dovrebbe essere di tipo Supplier<String>
simile a:
Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;
E poi il tutto si coalesce
riduce semplicemente a o.get()
.
Per un esempio più concreto:
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()
e ageFromInput()
sarebbe già tornato Optional<Integer>
, naturalmente.
E poi coalesce
diventa effectiveAge.get()
o semplicemente effectiveAge
se siamo felici con a Supplier<Integer>
.
IMHO, con Java 8 vedremo sempre più codice strutturato in questo modo, poiché è estremamente autoesplicativo ed efficiente allo stesso tempo, specialmente in casi più complessi.
Mi manca una classe Lazy<T>
che invoca una Supplier<T>
sola volta, ma pigramente, così come la coerenza nella definizione di Optional<T>
(cioè Optional<T>
- Optional<T>
operatori, o anche Supplier<Optional<T>>
).