Возвратите необязательный параметр как есть, если возвращенный необязательный параметр имеет значение, иначе вызовите другую функцию

У меня есть два метода func1 и func2, которые возвращают необязательно. Возвратите необязательный как есть, если возвращенный необязательный из func1 имеет значение, в противном случае вызовите func2 и верните его необязательный. Один из способов — использовать if-else.

Optional<MyObject> opt1 = func1();
if (opt1.isPresent()) {
    return opt1;
}
return func2();

Однако я хочу добиться этого, используя Java 8 Optional и избегая if-else.

Что-то вроде:

return Optional.of(obj1) 
        .flatMap_returnOptionalIfvaluePresent(func1)
        .orElseReturnOptionalFromThis(func2)

Может ли кто-нибудь предложить хороший способ для этого?


person adimoh    schedule 18.01.2019    source источник
comment
Что такое func1 и func2? Если это методы, переформатируйте код, чтобы он был действительным. Предоставьте ожидаемые входные данные и желаемые результаты. Укажите if-else, чтобы сделать вопрос более ясным.   -  person Nikolas Charalambidis    schedule 18.01.2019
comment
Почему вы хотите избежать ясного и простого if-else для трудночитаемого способа?   -  person vincrichaud    schedule 18.01.2019
comment
Это может быть хорошим вопросом, но в настоящее время неясно, чего вы хотите. Опубликуйте свой код, который использует if-else, чтобы было очевидно, чего вы пытаетесь достичь.   -  person Michael    schedule 18.01.2019
comment
@ Майкл, я с вами здесь, если ОП придет, чтобы объяснить больше, это может стать довольно хорошим вопросом.   -  person Eugene    schedule 18.01.2019


Ответы (5)


Изменить: or

Java 9 и более поздние версии предлагают очень элегантное решение:

Optional<String> myFunc() {
    return func1().or(this::func2);
}

or (представленный в Java 9) делает именно то, о чем вы просили: если Optional, возвращаемое из func1, имеет значение, оно возвращается (или эквивалентное Optional). Если нет, вызывается поставщик (здесь func2()) для получения Optional, который затем возвращается.

Ява 8

Есть несколько способов. В Java 8 я предпочитаю брать значения из Optional из func1 и func2:

Optional<String> myFunc() {
    String returnValue = func1().orElse(func2().orElse(null));
    return Optional.ofNullable(returnValue);
}

Редактировать 2: альтернативное предложение @Holger в комментарии достаточно хорошо для цитирования в ответе (Хольгер, возможно, вы разместили его как комментарий только потому, что вопрос закрыт, и поэтому вы не могли опубликовать свой собственный отвечать):

    return func1().map(Optional::of).orElse(func2());

Это происходит наоборот: отображение с использованием Optional::of оборачивает Optional из func1 внутрь, но Optional только в том случае, если оно имеет значение, из которого orElse снова разворачивает его.

Если вызов func2 обходится дорого, вы можете избежать его, когда он не нужен (когда func1 предоставляет значение):

    String returnValue = func1().orElseGet(() -> func2().orElse(null));

Или в версии Хольгера:

    return func1().map(Optional::of).orElseGet(this::func2);

isPresent, используемый в нескольких других ответах, настолько низкоуровневый, что я использую его редко и только в крайнем случае.

person Ole V.V.    schedule 18.01.2019
comment
Есть ли дополнительный API для устранения return Optional.ofNullable(returnValue); - person adimoh; 18.01.2019
comment
Нет, @adimoh, но вы, конечно, можете вставить это, если хотите: return Optional.ofNullable(func1().orElse(func2().orElse(null)));. - person Ole V.V.; 18.01.2019
comment
@ОлеВ.В. java-9 or - это то, что нужно, но в то же время я не вижу ничего плохого в чем-то вроде public static <T> Optional<T> find(Optional<T> left, Optional<T> right) { return left.isPresent() ? left : right; }.. 1+ - person Eugene; 18.01.2019
comment
Использование func1().orElseGet(() -> func2().orElse(null)) принесет небольшое улучшение, так как func2 не будет выполняться жадно. Однако хорошие решения. - person ernest_k; 18.01.2019
comment
Да, @ernest_k, именно это я и сказал в конце ответа. Великие умы думают одинаково. :-) - person Ole V.V.; 18.01.2019
comment
@Michael Очень близкий дубликат. В этом вопросе нет вызовов методов func1 и func2, по крайней мере, явно (вероятно, два Optional будут исходить из вызовов методов), что, как мне кажется, добавляет небольшой поворот к этому вопросу. - person Ole V.V.; 18.01.2019
comment
return func1().map(Optional::of).orElse(func2()); или, для дорогостоящей func2 операции, return func1().map(Optional::of).orElseGet(this::func2); - person Holger; 18.01.2019

Если вы используете java 9+, вы можете просто использовать Optional.or:

return func1().or(() -> func2());

В Java 8 вам может потребоваться создать новый необязательный параметр из результатов (используйте orElseGet, чтобы избежать нетерпеливого выполнения):

return Optional.ofNullable(func1().orElseGet(() -> func2().orElse(null)));
person ernest_k    schedule 18.01.2019

Как насчет чего-то вроде

Object value1 = func1();
return value1.isPresent() ? value1 : func2();

Если я неправильно понял, что вы после этого вернете значение из первой функции, если оно присутствует, а если оно не существует, вызовите func2(), чтобы вернуть второй необязательный. Вероятно, вы могли бы упростить его до func1().isPresent, но это сделало его немного менее ясным.

person Nicholas Smith    schedule 18.01.2019

Это было бы что-то вроде этого, если я все правильно понял:

Optional.of(obj1)
        .filter(obj -> func1().isPresent())
        .orElse(func2());
person Artur Vakhrameev    schedule 18.01.2019
comment
orElse вернуть значение Необязательно. Я хочу вернуть себя Необязательный. - person adimoh; 18.01.2019
comment
orElse возвращает результат функции func2() и возвращает необязательно, не так ли? - person Artur Vakhrameev; 18.01.2019

Вот более общая версия, работающая с n функциями:

private static <T> Optional<T> firstPresent(Supplier<Optional<T>>... optionals) {
    return Stream.of(optionals)
            .map(Supplier::get)
            .filter(Optional::isPresent)
            .findFirst()
            .orElse(Optional.empty());
}

Для использования следующим образом:

    Optional<String> result = firstPresent(() -> func1(null), () -> func2("abc"));
person Benoit    schedule 18.01.2019