可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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