Reputation: 9922
I have two java.util.Optional
instances and I want to get an Optional
that either:
Is there a straight-forward way to do that, i.e. is there already some API to do that?
The following expressions will do that, but I have to mention the first optional twice:
firstOptional.isPresent() ? firstOptional : secondOptional
This is exactly what com.google.common.base.Optional.or()
does, but that method is not present in Java 8's API.
The accepted answer by aioobe lists a few alternative approaches to overcome this omission of the Optional
API right where such a value has to be computed (which answers my question). I've now opted to add a utility function to my codebase:
public static <T> Optional<T> or(Optional<T> a, Optional<T> b) {
if (a.isPresent())
return a;
else
return b;
}
Upvotes: 68
Views: 42150
Reputation: 375
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();
}
?
Upvotes: 1
Reputation: 421030
firstOptional.or(() -> secondOptional);
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());
Upvotes: 90
Reputation: 162
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.
Upvotes: 9
Reputation: 494
I know this question is old, but why don't just use in this kind of cases something proven like Chain-of-responsibility pattern? It is made/designed for cases like yours. And as an additional benefit it's quite easy to add additional services to the list.
Here is a link that describes the Pattern: https://sourcemaking.com/design_patterns/chain_of_responsibility
Upvotes: -2
Reputation: 3959
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()
.
Upvotes: 10