19

In Optional while optional.orElse method is call, irrespective of the element is present or not the orElse part is executed it does not behave as the if else condition.

In the below code if you see in Case 1 both getNullPoJo and getDefaultPoJo is executed since getNullPoJo will return empty Optional

In Case 2 where you will get a Optional with loaded value (from getLoadedPoJo) also you getDefaultPoJo is executed

I am just trying to understand the working of optional.orElse.

public static void main (String [] a) {
    PoJo poJo1=getNullPoJo().orElse(getDefaultPoJo());//Case 1
    System.out.println("pojo1 Got "+poJo1.getVariable());
    PoJo poJo2=getLoadedPoJo().orElse(getDefaultPoJo());//Case 2
    System.out.println("pojo2 Got "+poJo2.getVariable());
}

private static Optional<PoJo> getNullPoJo() {
    System.out.println("Executing getNullPoJo");
    Optional<PoJo> optional=Optional.empty();
    return optional;
}

private static Optional<PoJo> getLoadedPoJo() {
    System.out.println("Executing getLoadedPoJo");
    PoJo poJo =new PoJo();
    poJo.setVariable("Loaded");
    Optional<PoJo> optional=Optional.of(poJo);
    return optional;
}

private static PoJo getDefaultPoJo() {
    System.out.println("Executing getDefaultPoJo");
    PoJo poJo =new PoJo();
    poJo.setVariable("Default");
    return poJo;
}

The current Output is:

Executing getNullPoJo

Executing getDefaultPoJo

pojo1 Got Default

Executing getLoadedPoJo

Executing getDefaultPoJo

pojo2 Got Loaded

My Expected Output is:

Executing getNullPoJo

Executing getDefaultPoJo

pojo1 Got Default

Executing getLoadedPoJo

pojo2 Got Loaded

I do not want the call to getDefaultPoJo in Case 2

Community
  • 1
  • 1
Kishore Chandran
  • 457
  • 4
  • 12
  • 5
    Possible duplicate of [Difference between \`Optional.orElse()\` and \`Optional.orElseGet()\`](https://stackoverflow.com/questions/33170109/difference-between-optional-orelse-and-optional-orelseget) – manish Jun 24 '19 at 08:15
  • 1
    @manish Though it may be reasonable to use `orElseGet` here, the question isn't about it: OP's confusion comes from a faulty analogy between the method `Optional#orElse` and the control flow statement `if-else`. We shouldn't close it. – Andrew Tobilko Jun 24 '19 at 20:30

3 Answers3

18

Use orElseGet() to avoid evaluating getDefaultPoJo() when the Optional is not empty:

PoJo poJo1=getNullPoJo().orElseGet(() -> getDefaultPoJo());
PoJo poJo2=getLoadedPoJo().orElseGet(() -> getDefaultPoJo());
Eran
  • 387,369
  • 54
  • 702
  • 768
15
getNullPoJo().orElse(getDefaultPoJo());

It's a method chain, and every method in this chain will get executed, no matter how the underlying API is supposed to work.

1) getNullPoJo()
2) r = getDefaultPoJo()
3) orElse(r)  

In order to execute a method, its actual parameters must be evaluated. To call orElse(getDefaultPoJo()), getDefaultPoJo() must be invoked as well. That's the reason you are getting more than you expected.

Usually, you will see

.orElse(null);
.orElse(defaultValue);

where null, and defaultValue are predefined values that don't require any calculations.

On the other hand, we write

.orElseGet(() -> generateDefaultValue());
.orElseGet(() -> calculateDefaultOutcome());

where generateDefaultValue and calculateDefaultOutcome are methods that do perform some calculations (intensive ones or ones we don't want to execute until the right moment [your case]).

Compare,

.orElseGet(() -> createDefaultPoJo());
.orElse(DEFAULT_POJO);

where DEFAULT_POJO is a variable initialised prior to this method call, and createDefaultPoJo() is a method that creates a default instance every time it gets called.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
5

The output is correct, Optional.orElse() will allways execute the else-action. (the expression you provide) Use orElseGet() -which only calls the function if Optional.isPresent == false- for your desired output:

Difference between `Optional.orElse()` and `Optional.orElseGet()`

https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#orElseGet-java.util.function.Supplier-

ItFreak
  • 2,299
  • 5
  • 21
  • 45