Pour être complet, le cas «plusieurs variables» est en effet possible, mais pas du tout élégant. Par exemple, pour les variables o
, p
et q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
Veuillez noter qu'il est utile de orElseGet()
s'occuper du cas qui o
, p
et q
ne sont pas des variables mais des expressions coûteuses ou avec des effets secondaires indésirables.
Dans le cas le plus général 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
Cela peut générer des expressions excessivement longues. Cependant, si nous essayons de passer à un monde sans null
, alors v[i]
sont très probablement déjà de typeOptional<String>
, par opposition à simplement String
. Dans ce cas,
result= o.orElse(p.orElse(q.get())) ;
ou dans le cas d'expressions:
result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;
De plus, si vous prépare également à un style fonctionnel déclarative, o
, p
et q
devrait être de typeSupplier<String>
comme dans:
Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;
Et puis le tout coalesce
réduit simplement à o.get()
.
Pour un exemple plus concret:
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()
et ageFromInput()
reviendraient déjà Optional<Integer>
, naturellement.
Et puis le coalesce
devienteffectiveAge.get()
ou simplement effectiveAge
si nous sommes satisfaits d'un Supplier<Integer>
.
IMHO, avec Java 8, nous verrons de plus en plus de code structuré comme celui-ci, car il est extrêmement auto-explicatif et efficace en même temps, en particulier dans les cas plus complexes.
Je manque une classe Lazy<T>
qui n'invoque Supplier<T>
qu'une seule fois, mais paresseusement, ainsi que la cohérence dans la définition de Optional<T>
(ie Optional<T>
- Optional<T>
opérateurs, ou même Supplier<Optional<T>>
).