Вы только что наткнулись на концепцию под названием поднятие в функциональном программировании, которая позволяет поднимать обычные функции (например, A -> B
) в новые домены (например, Optional<A> -> Optional<B>
).).
Существует также синтаксический сахар для flatMapping и картирования, более удобно называемый нотацией do в Haskell и аналогичных языках, и для понимания в Scala.Это дает вам возможность сохранить линейность потока и избежать вложения (что вы были вынуждены пройти в вашем примере 1).
Java, к сожалению, не имеет ничего подобного, поскольку его функциональные возможности программирования скудны,и даже Optional
на самом деле не первоклассный гражданин (никакой стандартный API на самом деле его не использует).Так что вы застряли на подходах, которые вы уже открыли.
Если вам интересны упомянутые выше концепции, читайте дальше.
Подъем
При условии, что у вас есть:
public String f(A a, B b) {
return b + "-" + a;
}
С его эквивалентом Scala:
def f(a: A, b: B) = b + "-" + a
Поднятие f
в Option
(то же, что Optional
в Java) будет выглядетьвот так (используя библиотеку Scalaz):
val lifted = Monad[Option].lift2(f)
lifted
теперь является функцией, эквивалентной:
public Optional<String> f(Optional<A> a, Optional<B> b) {
if(a.isPresent() && b.isPresent()) {
return Optional.of(b + "-" + a);
}
return Optional.empty;
}
Именно то, что вы ищете, в 1 строку, и работаетдля любого контекста (например, List
, а не только Option
) и любой функции.
Для понимания / Do запись
Использование для понимания , ваш пример будет выглядеть так (я думаю , у меня слабый Scala):
for {
a <- getA();
b <- getB();
} yield f(a, b)
И снова, это применимо ко всему, что может быть отображено на плоскости, например List
, Future
и т. Д.