Java8 orElse versus orElseGet – easily misused

So, the Java8 Optional has two really cool (and similar) functions: the orElse() and the orElseGet().

Java8 orElse vs orElseGet

If we quickly read the javadoc for each, we will only see a small difference;

  • one of them has a T type as a parameter and
  • the other has a function which must return with T (as a parameter).

Why can they be easily misused? What’s the difference? Let’s write some code! (Or use this if you are lazy!)

So, the code is simple, after the run we will see;

  • a and c is the long text from the function, and
  • b and d is “something”.

But what happened on the console? How many side effects did we get? 3! Why 3? That’s the million dollar question, that is, if you are writing code while you are half asleep, or before your first coffee. We need to go back to the basics.

The code above the line will be something like the code under the line when we compile it. If we apply this logic to the orElse, we will get something like this:

Sooo that’s why we have 3 side effects instead of 2.

If we read the javadoc again, we can see that the difference is bigger then we first thought. It says “other – the value to be returned if there is no value present, may be null” the VALUE.

 

What is confusing about this name? Why would a programmer ever misuse this? If you read something like “else,” you will associate something like:

But if we want to visualize the a.map(a ->func1(a)).orElse(func2()) – will get something like:

And why does the orElseGet have no side effects? Because it’s in the definition; “whose result is returned if no value is present”. It’s actually translated something like an if-else or ?: .

 

An interesting point of view is; we must minimize the functions with side effects in our codebase (like functional programming does), and we will fall harder into making mistakes like this. Additionally, it would be an interesting language/editor feature if we could tag the functions with side effects, and the IDE or the compiler would warn us when we do questionable things like writing a function to an “always will run” spot. Or if the VM optimized itself to not calculate never read variables (but it would cause other strange effects…).

If our function has no side effect its return value will be calculated, and dropped, but it will not cause any trouble (at least if it’s not calculated too slow). So basically the orElse can be used if you use only pure functional functions, but you could still have some unwanted behavior because of the unnecessary calculation time.

I think a much better naming could be orElse -> orElseConstant and orElseGet -> orElse.

 

So that’s why we should use orElseGet and not the orElse (or read carefully the javadoc at any hour)!

 

Gergő Törcsvári

Gergő Törcsvári

Software Developer at Wanari
I would love to change the world, but they won’t give me the source code (yet).