Solo per completezza, il caso "diverse variabili" è davvero possibile, sebbene non sia affatto elegante. Ad esempio, per le variabili o, pe q:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
Si prega di notare l'uso del orElseGet()caso che o, pe qnon 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 qdovrebbe 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 coalesceriduce 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 coalescediventa effectiveAge.get()o semplicemente effectiveAgese 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>>).