I'm still learning Javaslang/Vavr, so excuse the ignorance. The project I'm working on is stuck on Javaslang 2.1.0.
My question: is there a more "Functional" way (as opposed to imperative style) to structure my code to join multiple Trys only once they are successful?
I want to Try each input independently, the idea being to get as much as possible error information - I do not want to stop on the first error encountered (so orElse()
etc. won't do the trick). But once no errors are found any more, I want to do something further involving all of the inputs.
My current code looks like this (suitably anonymized):
Try<BigDecimal> amountTry = Try.of(this::readNumber)
.map(BigDecimal::valueOf)
.onFailure(this::collectError);
Try<Currency> currencyTry = Try.of(this::readString)
.map(currency -> currencyLookup(Currency.class, currency))
.onFailure(this::collectError);
if (amountTry.isSuccess() && currencyTry.isSuccess()) {
sale.setAmount(Amount.of(amountTry.get(), currencyTry.get()));
}
Can you suggest a pattern to replace the if()
with something more in the functional style of programming?
The Javaslang/Vavr construct that you are looking for is the for comprehension construct, which is accessible through the API.For
methods.
import javaslang.control.Try;
import static javaslang.API.For;
...
For(amountTry, currencyTry)
.yield(Amount::of)
.forEach(sale::setAmount);
That is, if both amountTry
and currencyTry
are non-empty, it creates an Iterable
by yielding a result value on the cross-product of the two iterables, and performing an action on each of the resulting elements by invoking a Consumer
. Here is the same in lambda form with explicit input types, if it helps you better understand it:
For(amountTry, currencyTry)
.yield((BigDecimal amount, Currency currency) -> Amount.of(amount, currency))
.forEach((Amount amount) -> sale.setAmount(amount));
Later versions of the library have overloads of the for comprehension for Try
which will return a Try
instance instead of Iterable
, which makes the API a little bit nicer if you want to stay in Try
domain.