Я работал с новым опциональным типом в Java 8 , и я столкнулся с тем, что кажется обычной операцией, которая не поддерживается функционально: "orElseOptional"
Рассмотрим следующую схему:
Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
Optional<Result> resultFromServiceB = serviceB(args);
if (resultFromServiceB.isPresent) return resultFromServiceB;
else return serviceC(args);
}
Существует много форм этого паттерна, но он сводится к желанию "orElse" для необязательного параметра, который принимает функцию, создающую новый необязательный параметр, вызываемый только в том случае, если текущий не существует.
Его реализация будет выглядеть так:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
Мне любопытно, есть ли причина, по которой такой метод не существует, если я просто использую Optional непреднамеренным образом, и какие другие способы люди придумали для решения этого случая.
Я должен сказать, что я думаю, что решения, включающие пользовательские служебные классы / методы, не элегантны, потому что люди, работающие с моим кодом, не обязательно будут знать, что они существуют.
Кроме того, если кто-нибудь знает, будет ли такой метод включен в JDK 9, и где я мог бы предложить такой метод? Мне кажется, это довольно вопиющее упущение в API.
orElseGet()
для того, что нужно OP, только он не генерирует хороший каскадный синтаксис.Ответы:
Это часть JDK 9 в форме
or
, которая занимаетSupplier<Optional<T>>
. Ваш пример будет:Для деталей смотрите Javadoc или этот пост, который я написал.
источник
ifPresent
. Но, во всяком случае, я думаю, что имяifPresent
не очень хорошее в любом случае. Для всех других методов , не имея «Else» в названии (какmap
,filter
,flatMap
), подразумевается , что они не делают ничего , если значение не присутствует, так зачемifPresent
...Optional<T> perform(Consumer<T> c)
метода, позволяющего создавать цепочкиperform(x).orElseDo(y)
(orElseDo
в качестве альтернативы вашему предложениюifEmpty
, чтобы быть последовательнымelse
в имени всех методов, которые могли бы что-то сделать для отсутствующих значений). Вы можете имитировать этоperform
в Java 9 через,stream().peek(x).findFirst()
хотя это злоупотребление API, и до сих пор нет способа выполнить a,Runnable
не указавConsumer
одновременно ...Самый чистый подход «попробуй сервисы», учитывая текущий API, будет:
Важным аспектом является не (постоянная) цепочка операций, которую вы должны написать один раз, а то, насколько просто добавить другую службу (или изменить список служб, как правило). Здесь, добавление или удаление одного
()->serviceX(args)
достаточно.Из-за ленивой оценки потоков никакая служба не будет вызвана, если предыдущая служба вернула непустую
Optional
.источник
.map(Optional::get)
с «.findFirst()
легче» «читать», например,.filter(Optional::isPresent).findFirst().map(Optional::get)
можно «прочитать» как «найти первый элемент в потоке, для которого Optional :: isPresent имеет значение true, а затем сгладить его, применив Optional :: get»?Это не красиво, но это будет работать:
.map(func).orElseGet(sup)
это довольно удобный шаблон для использования сOptional
. Это означает «Если этоOptional
содержит ценностьv
, дай мнеfunc(v)
, иначе дай мнеsup.get()
».В этом случае мы звоним
serviceA(args)
и получаемOptional<Result>
. Если этоOptional
содержит значениеv
, мы хотим получитьOptional.of(v)
, но если оно пустое, мы хотим получитьserviceB(args)
. Промыть-повторить с большим количеством альтернатив.Другое использование этого шаблона
.map(Stream::of).orElseGet(Stream::empty)
.map(Collections::singleton).orElseGet(Collections::emptySet)
источник
() -> {}
не возвращаетOptional
. Что вы пытаетесь достичь?or(Supplier<Optional<T>>)
Java 9.map()
на пустомOptional
будет производить пустоеOptional
.Возможно, это то, что вам нужно: получить значение от одного дополнительного или другого
В противном случае, вы можете посмотреть
Optional.orElseGet
. Вот пример того, что я думаю, что вы после:источник
ofNullable
в самое крутое, что я когда-либо видел.Предполагая, что вы все еще на JDK8, есть несколько вариантов.
Вариант № 1: создайте свой собственный вспомогательный метод
Например:
Чтобы вы могли сделать:
Вариант № 2: использовать библиотеку
Например, google guava Optional поддерживает правильную
or()
работу (так же, как JDK9), например:(Где каждая из услуг возвращается
com.google.common.base.Optional
, а неjava.util.Optional
).источник
Optional<T>.or(Supplier<Optional<T>>)
в документах Guava. У вас есть ссылка для этого?Это выглядит как подходящее для сопоставления с образцом и более традиционного интерфейса Option с реализациями Some и None (например, в Javaslang , FunctionalJava ) или с отложенной реализацией Maybe в cyclops-реагировать. Я являюсь автором этой библиотеки.
С помощью циклоп-реакции вы также можете использовать структурное сопоставление с образцом в типах JDK. Для Необязательного вы можете сопоставить существующие и отсутствующие случаи с помощью шаблона посетителя . это будет выглядеть примерно так -
источник