5

I have two methods func1 and func2 which return Optional. Return Optional as it is if the returned Optional from func1 has value, else call func2 and return its Optional. One way is to use if-else.

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

However, I wish to achieve it using Java 8 Optional and avoid if-else.

Something like:

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

Can anyone suggest a good way for it?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
adimoh
  • 658
  • 2
  • 8
  • 20
  • What is `func1` and `func2`? If they are methods, please reformat your code to be valid. Provide the expected inputs and desired outputs. Provide the `if-else` to make the question clearer. – Nikolas Charalambidis Jan 18 '19 at 09:47
  • Why would you want to avoid a clear and simple `if-else` for a hard-to-read way ? – vincrichaud Jan 18 '19 at 09:49
  • 2
    This has the potential to be a good question but it's currently not clear what you want. Post your code that uses `if-else` so that its obvious what you're trying to achieve. – Michael Jan 18 '19 at 09:53
  • @Michael I am with you here, if the OP comes to explain more, this has the potential to be a fairly good question – Eugene Jan 18 '19 at 09:58

5 Answers5

7

Edit: or

Java 9 and later offer a very elegant solution:

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

or (introduced in Java 9) does exactly what you asked for: If the Optional returned from func1 has a value, it is returned (or an equivalent Optional). If not, the supplier (here func2()) is invoked to get an Optional, which is then returned.

Java 8

There are several ways. In Java 8 I prefer to take the values out of the Optionals from func1 and func2:

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

Edit 2: @Holger’s alternative suggestion in a comment is good enough for quoting within the answer (Holger, you may have posted it as a comment only because the question is closed and you therefore could not post your own answer):

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

It goes the opposite way: The mapping using Optional::of wraps the Optional from func1 inside yet an Optional only if it has a value, from which orElse unwraps it again.

If the call to func2 is expensive, you may want to avoid it when it’s not needed (when func1 supplies a value):

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

Or in Holger’s version:

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

isPresent used in a couple of other answers is so low-level, I seldom use it and only as a last resort.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Is there any Optional API to eliminate `return Optional.ofNullable(returnValue);` – adimoh Jan 18 '19 at 10:07
  • No, @adimoh, but you may of course inline it if you prefer: `return Optional.ofNullable(func1().orElse(func2().orElse(null)));`. – Ole V.V. Jan 18 '19 at 10:19
  • @OleV.V. the java-9 `or` is the way to go here, but at the same time I see nothing wrong with something like `public static Optional find(Optional left, Optional right) { return left.isPresent() ? left : right; }`.. 1+ – Eugene Jan 18 '19 at 10:29
  • 2
    Using `func1().orElseGet(() -> func2().orElse(null))` will bring a slight improvement as `func2` wouldn't be executed eagerly. Good solutions though. – ernest_k Jan 18 '19 at 10:35
  • 2
    Yes, @ernest_k, that’s exactly what I say near the bottom of the answer. Great minds think alike. :-) – Ole V.V. Jan 18 '19 at 10:36
  • @Michael A very near duplicate. That question doesn’t have the method calls to `func1` and `func2`, at least not explicitly (likely the two `Optional`s would come from method calls, though), which does add a little twist to this question the way I see it. – Ole V.V. Jan 18 '19 at 10:38
  • 1
    `return func1().map(Optional::of).orElse(func2());` or, for an expensive `func2` operation, `return func1().map(Optional::of).orElseGet(this::func2);`… – Holger Jan 18 '19 at 14:51
2

If you're using java 9+, you can just use Optional.or:

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

In Java 8, you may need to create a new Optional from results (use orElseGet to avoid eager execution):

return Optional.ofNullable(func1().orElseGet(() -> func2().orElse(null)));
ernest_k
  • 44,416
  • 5
  • 53
  • 99
0

What about something like

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

Unless I've misunderstood what you're after that will return the value from the first function if it's present, and if it doesn't exist then call func2() to return the second optional. You could probably simplify it further to func1().isPresent but it made it a little less clear.

Nicholas Smith
  • 11,642
  • 6
  • 37
  • 55
0

It would be something lke this, if i usterstand everything correctly:

Optional.of(obj1)
        .filter(obj -> func1().isPresent())
        .orElse(func2());
Artur Vakhrameev
  • 794
  • 7
  • 11
0

Here is a more generic version, working with n functions:

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

To be used like this:

    Optional<String> result = firstPresent(() -> func1(null), () -> func2("abc"));
Benoit
  • 5,118
  • 2
  • 24
  • 43