6

The below code prints:

should Not have called
hello world

Why is orElse getting executed even when we have an Optional that contains a value?

public static void main(String[] args){
    String o = Optional.ofNullable("world").map(str -> "hello" + str).orElse(dontCallMe());
    System.out.println(o);
}

private static String dontCallMe() {
    System.out.println("should Not have called");
    return "why god why";
}
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
Bharat Bhagat
  • 381
  • 1
  • 5
  • 14

2 Answers2

11

The orElse method looks like this:

public T orElse(T other) {
   return value != null ? value : other;
}

There isn't any complex logic here.

As with any method, it will do the following:

  • Get the actual values of all parameters passed to the method (which includes calling any methods in those parameters).
  • Pass those parameters to the method.
  • Execute the method.

The fact that we don't actually care about the value of the parameter doesn't change this process (this is just the way the language has been designed, for better or worse).


If you're looking to not call the method in the parameter, you're probably looking for Optional.orElseGet.

This:

public static void main(String[] args){
    String o = Optional.ofNullable("world").map(str -> "hello" + str)
                   .orElseGet(() -> dontCallMe());
    System.out.println(o);
}

private static String dontCallMe() {
    System.out.println("should not have called");
    return "why oh why";
}

Outputs only:

helloworld

The difference here is that the thing (Supplier) we're passing to the method will stay () -> dontCallMe(), it does not become () -> "why oh why" - only when you call get does it actually evaluate what's going on there and does dontCallMe actually get called.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • Nice! Suggesting orElseGet for example purposes is all good but I’d like to add something more. one should only use this method if the operation to be performed is computationally expensive otherwise resort to orElse. – Ousmane D. Mar 31 '18 at 12:59
2

Please, can somebody explain why orElse is getting executed event after map will get executed for final result.

With the orElse method regardless if the wrapped value is present or not, the default object is created.

Hence when you call the function dontCallMe() in the orElse to return the string value; "should Not have called" will be printed to the console.

Using orElseGet instead of orElse would provide the result you expected although you should only use this method either when the default value is computationally expensive to create or you want to be sure this is done if and only if the value is absent (empty optional) in which case it's a necessity.

As an aside, there's no need to use Optional.ofNullable here, the Optional.of method is more appropriate as the former should only be used if the argument can be null and the latter only if the argument cannot be null.

As a reading, you can check out this good post on the baeldung site.

Guide To Java 8 Optional

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • 1
    point is, in `orElseGet` you are providing a `Supplier` which delegates the creation code only when needed. the other good example where this is done are loggers – Eugene Mar 31 '18 at 15:40