Get value from one Optional or another
I had a few encounters with a problem that might've been solved with JDK 9 Optional::or
and couldn't because we use JDK 8. Finally I added a util class with this method:
@SafeVarargs
public static <T> Optional<T> firstPresent(final Supplier<Optional<T>>... optionals) {
return Stream.of(optionals)
.map(Supplier::get)
.filter(Optional::isPresent)
.findFirst()
.orElse(Optional.empty());
}
Now you can supply any number of optionals to this method and they'll be lazily evaluated like so:
final Optional<String> username = OptionalUtil.firstPresent(
() -> findNameInUserData(user.getBasicData()),
() -> findNameInUserAddress(user.getAddress()),
() -> findDefaultUsername());
Now, findNameInUserAddress
will only be called if findNameInUserData
returns empty. findDefaultUsername
will only be called if both findNameInUserData
and findNameInUserAddress
return empty etc.
Why not just (Supplier
wrapper can be easily added):
@SafeVarargs
public static <T> Optional<T> firstPresent(Optional<T>... optionals) {
return Stream.of(optionals)
.flatMap(Optional::stream)
.findFirst();
}
?
EDIT: I totally thought you were using Guava's Optional
originally. I've updated my answer to supply both Guava and Java 8 syntax for their respective Optional
classes.
Java 8 Optional
You can shorten it up to this:
firstOptional.orElse(secondOptional.orElse(EMPTY_VALUE))
I'm not sure what you meant in your third bullet by "empty". If you meant null then this'll do the trick:
firstOptional.orElse(secondOptional.orElse(null))
orElse()
is a method on Optional
that will return the value if present, otherwise it will return the value you supplied as the argument to orElse()
.
Guava Optional
You can shorten it up to this:
firstOptional.or(secondOptional.or(EMPTY_VALUE))
I'm not sure what you meant in your third bullet by "empty". If you meant null then this'll do the trick:
firstOptional.or(secondOptional.orNull())
or()
is a method on Optional
that will return the value if present, otherwise it will return the value you supplied as the argument to or()
.
Java 9 and above:
firstOptional.or(() -> secondOptional);
Java 8 and below
If you want to avoid mentioning firstOptional
twice, you'd probably have to go with something like
firstOptional.map(Optional::of).orElse(secondOptional);
or
Optional.ofNullable(firstOptional.orElse(secondOptional.orElse(null)));
But the most readable variant is probably to simply do
Optional<...> opt = firstOptional.isPresent() ? firstOptional
: secondOptional.isPresent() ? secondOptional
: Optional.empty();
If someone stumbles across this question but has a list of optionals, I'd suggest something like
Optional<...> opt = optionals.stream()
.filter(Optional::isPresent)
.findFirst()
.orElse(Optional.empty());