What's the most elegant way to combine optionals?
Try this:
firstChoice().map(Optional::of)
.orElseGet(this::secondChoice);
The map method gives you an Optional<Optional<Foo>>
. Then, the orElseGet
method flattens this back to an Optional<Foo>
. The secondChoice
method will only be evaluated if firstChoice()
returns the empty optional.
Maybe something like this:
Optional<String> finalChoice = Optional.ofNullable(firstChoice()
.orElseGet(() -> secondChoice()
.orElseGet(() -> null)));
From: Chaining Optionals in Java 8
You can simply replace that with,
Optional<Foo> firstChoice = firstChoice();
return firstChoice.isPresent()? firstChoice : secondChoice();
The above code won't call unless firstChoice.isPresent() is false.
But you have to be prepare to call both functions to get the desired output. There is no other way to escape the checking.
- Best case is First choice returning true.
- Worst case will be First choice returning false, hence another method call for second choice.
Here's the generalization of @marstran solution for any number of optionals:
@SafeVarargs
public static <T> Optional<T> selectOptional(Supplier<Optional<T>>... optionals) {
return Arrays.stream(optionals)
.reduce((s1, s2) -> () -> s1.get().map(Optional::of).orElseGet(s2))
.orElse(Optional::empty).get();
}
Test:
public static Optional<String> first() {
System.out.println("foo called");
return Optional.empty();
}
public static Optional<String> second() {
System.out.println("bar called");
return Optional.of("bar");
}
public static Optional<String> third() {
System.out.println("baz called");
return Optional.of("baz");
}
public static void main(String[] args) {
System.out.println(selectOptional(() -> first(), () -> second(), () -> third()));
}
Output:
foo called
bar called
Optional[bar]