Solo para completar, el caso de "varias variables" es realmente posible, aunque no es elegante en absoluto. Por ejemplo, para las variables o
, p
y q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
Tenga en cuenta el uso de orElseGet()
asistir al caso de que o
, p
yq
no son variables sino expresiones caros o con efectos secundarios no deseados.
En el caso más general 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
Esto puede generar expresiones excesivamente largas. Sin embargo, si estamos tratando de mudarnos a un mundo sin él null
, entonces v[i]
lo más probable es que ya seamos de tipo Optional<String>
, en lugar de simplemente String
. En este caso,
result= o.orElse(p.orElse(q.get())) ;
o en el caso de expresiones:
result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;
Por otra parte, si también se está moviendo a un estilo funcional declarativa, o
, p
, y q
debe ser de tipo Supplier<String>
como en:
Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;
Y luego todo se coalesce
reduce simplemente ao.get()
.
Para un ejemplo más 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()
Y ageFromInput()
sería ya volverOptional<Integer>
, naturalmente.
Y luego se coalesce
convierte effectiveAge.get()
o simplemente effectiveAge
si estamos contentos con unSupplier<Integer>
.
En mi humilde opinión, con Java 8 veremos más y más código estructurado de esta manera, ya que es extremadamente autoexplicativo y eficiente al mismo tiempo, especialmente en casos más complejos.
Echo de menos una clase Lazy<T>
que invoca Supplier<T>
solo una vez, pero perezosamente, así como la coherencia en la definición de Optional<T>
(es decir Optional<T>
, Optional<T>
operadores, o incluso Supplier<Optional<T>>
).