Получить значение из одного Необязательного или другого
У меня есть два экземпляра java.util.Optional
, и я хочу получить Optional
, который:
- Имеет значение first Optional, если оно имеет значение.
- Значение второго необязательно, если оно имеет значение.
- Пусто от ни одного параметра не имеет значения.
Есть ли прямой способ сделать это, т.е. уже есть какой-нибудь API для этого?
Следующие выражения сделают это, но я должен упомянуть первый необязательный дважды:
firstOptional.isPresent() ? firstOptional : secondOptional
Это именно то, что делает com.google.common.base.Optional.or()
, но этот метод отсутствует в Java 8 API.
В принятом ответе aioobe перечислены несколько альтернативных подходов для преодоления этого упущения API-интерфейса Optional
, где такое значение должно быть вычислено (что отвечает на мой вопрос). Теперь я решил добавить служебную функцию в свою кодовую базу:
public static <T> Optional<T> or(Optional<T> a, Optional<T> b) {
if (a.isPresent())
return a;
else
return b;
}
Ответы
Ответ 1
Обновление: Начиная с Java 9 (changeet 12885) вы можете сделать
firstOptional.or(() -> secondOptional);
Для Java 8, читайте дальше...
Если вы хотите не упоминать firstOptional
дважды, вам, вероятно, придется пойти с чем-то вроде
firstOptional.map(Optional::of).orElse(secondOptional);
или
Optional.ofNullable(firstOptional.orElse(secondOptional.orElse(null)));
Но наиболее читаемым вариантом, вероятно, просто сделать
Optional<...> opt = firstOptional.isPresent() ? firstOptional
: secondOptional.isPresent() ? secondOptional
: Optional.empty();
Если кто-то споткнется по этому вопросу, но имеет список опций, я бы предложил что-то вроде
Optional<...> opt = optionals.stream()
.filter(Optional::isPresent)
.findFirst()
.orElse(Optional.empty());
Ответ 2
EDIT: Я полностью думал, что вы использовали Guava Optional
изначально. Я обновил свой ответ, чтобы предоставить синтаксис Guava и Java 8 для соответствующих классов Optional
.
Java 8 Дополнительно
Вы можете сократить его до:
firstOptional.orElse(secondOptional.orElse(EMPTY_VALUE))
Я не уверен, что вы имели в виду в своей третьей пуле, "пустой". Если вы имели значение null, то это будет трюк:
firstOptional.orElse(secondOptional.orElse(null))
orElse()
- это метод на Optional
, который вернет значение, если оно присутствует, иначе оно вернет значение, которое вы предоставили в качестве аргумента orElse()
.
Guava Необязательный
Вы можете сократить его до:
firstOptional.or(secondOptional.or(EMPTY_VALUE))
Я не уверен, что вы имели в виду в своей третьей пуле, "пустой". Если вы имели значение null, то это будет трюк:
firstOptional.or(secondOptional.orNull())
or()
- это метод на Optional
, который вернет значение, если оно присутствует, иначе оно вернет значение, которое вы предоставили в качестве аргумента or()
.
Ответ 3
У меня было несколько встреч с проблемой, которая могла быть решена с помощью JDK 9 Optional::or
и не могла, потому что мы используем JDK 8. Наконец, я добавил класс util с помощью этого метода:
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());
Теперь вы можете предоставить любое количество опций этому методу, и они будут лениво оценены так:
final Optional<String> username = OptionalUtil.firstPresent(
() -> findNameInUserData(user.getBasicData()),
() -> findNameInUserAddress(user.getAddress()),
() -> findDefaultUsername());
Теперь findNameInUserAddress
вызывается только в том случае, если findNameInUserData
возвращает пустое. findDefaultUsername
будет вызываться только в том случае, если оба findNameInUserData
и findNameInUserAddress
возвращаются пустым и т.д.
Ответ 4
Я знаю, что этот вопрос устарел, но почему бы просто не использовать в подобных случаях что-то вроде шаблона цепочки ответственности? Он изготовлен/предназначен для таких случаев, как ваш. И в качестве дополнительного преимущества довольно легко добавить дополнительные сервисы в список.
Вот ссылка, которая описывает шаблон: https://sourcemaking.com/design_patterns/chain_of_responsibility