by Rahel Lüthy
Tony Hoare, inventor of the
null reference, apologetically called it “the billion dollar mistake”.
The problem with
null is not that it was invented back in 1965, but that we are still struggling with it 50 years later. Any Java developer has probably seen and written code like this:
In fact, most Java monoglots have probably seen and written code like this so many times, that they don’t even see the problem anymore. And yet, with Java 8, they have to deal with a solution: the
I recently came across this popular article: Embracing the Void: 6 Refined Tricks for Dealing with Nulls in Java. It gives a nice rundown of strategies around the
null reference. Sadly, it discourages the use of Java 8’s
Optional. In this post I will explain why the argumentation is flawed.
One way to re-write the above snippet using
Optional could look like this:
The service returns an
Optional<String> and the caller is working her way around it. From a complexity point of view, the change is argueably not much of an improvement: We still need a mutable
value variable, and the overall logic is roughly the same. And yet, the expressiveness has improved. The signature of the service has clearer semantics now. Originally, the caller of the service could not distinguish between “the implementor of the service made a programming error” and “the value has not been found” – both were resulting in
null. This is possible now and – even better – the type system forces the caller to deal with absents values.
Now that the semantics are straight, let’s make the
value variable immutable and eliminate the
if .. else construct:
This code is safer, more expressive, and more concise than the original version, but the
() -> "..." clutter makes my Scala heart cringe, so I’m offering yet another variant:
We are taking advantage of the fact that
Optional behaves like a collection: If it is absent, it behaves like an empty list, the call to
map is never executed, and the result is an empty
Optional (which we handle via
orElse). If the result is present, it behaves like a list with one element, which we trim and return.
Imagine that our original
service interface is actually coming from a 3rd party library. You can’t simply change all the signatures to properly return
Option<T>. But you can wrap the service calls and create yourself a
And finally: The holy grail of functional programming,
Let’s start with a simple
User which has an optional middle name:
Looking up the user via service is straightforward, but look at all those types:
Optional is the result of the
map call (presence/absence of
User), while the inner
Optional is wrapping the middle name value.
flatMap is our power tool to unwrap the value from nested
So next time you can’t remember the semantics of
flatMap, just think of all those cats stuck in their nested boxes:
I highly recommend The Neophyte’s Guide to Scala - Part 5: The Option Type for anyone interested in further details.