Просто для полноты, случай «нескольких переменных» действительно возможен, хотя и вовсе не элегантен. Например, для переменных o
, p
и q
:
Optional.ofNullable( o ).orElseGet(()-> Optional.ofNullable( p ).orElseGet(()-> q ) )
Пожалуйста, обратите внимание на orElseGet()
то o
, что использование , p
и q
не являются переменными, а выражениями, дорогими или с нежелательными побочными эффектами.
В самом общем случае 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
Это может генерировать выражения чрезмерно долго. Однако, если мы пытаемся перейти в мир без null
, то v[i]
, скорее всего, это уже тип Optional<String>
, а не просто String
. В таком случае,
result= o.orElse(p.orElse(q.get())) ;
или в случае выражений:
result= o.orElseGet(()-> p.orElseGet(()-> q.get() ) ) ;
Кроме того, если вы также переход к функционально-декларативному стилю o
, p
и q
должно быть типа , Supplier<String>
как в:
Supplier<String> q= ()-> q-expr ;
Supplier<String> p= ()-> Optional.ofNullable(p-expr).orElseGet( q ) ;
Supplier<String> o= ()-> Optional.ofNullable(o-expr).orElseGet( p ) ;
И тогда все coalesce
сводится просто к o.get()
.
Для более конкретного примера:
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()
И ageFromInput()
было бы уже вернуться Optional<Integer>
, естественно.
И тогда coalesce
становится effectiveAge.get()
или просто effectiveAge
если мы довольны собой Supplier<Integer>
.
ИМХО, с Java 8 мы увидим все больше и больше такого структурированного кода, поскольку он чрезвычайно понятен и эффективен одновременно, особенно в более сложных случаях.
Я действительно пропускаю класс, Lazy<T>
который вызывает Supplier<T>
только один раз, но лениво, а также последовательность в определении Optional<T>
(то есть Optional<T>
- Optional<T>
операторы или даже Supplier<Optional<T>>
).