可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have two java.util.Optional
instances and I want to get an Optional
that either:
- Has the value of the first Optional, if it has a value.
- Has the value of the second Optional, if it has a value.
- Is empty of neither Optional has a value.
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 Optional or(Optional a, Optional b) { if (a.isPresent()) return a; else return b; }
回答1:
Update: As of Java 9 (changeset 12885) you can do
firstOptional.or(() -> secondOptional);
For Java 8, read on...
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());
回答2:
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()
.
回答3:
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:
public static Optional firstPresent(final Supplier>... 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 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.
回答4:
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