Java’s Optional type and dealing with Null
Sir Tony Hoare, a British computer scientist famously said at a conference about his invention of the null pointer reference:
“I call it my billion-dollar mistake”
it has..“led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.”
Yikes! Sounds bad. But why is it so bad?
What is Null?
In Java a null value is for representing the concept of a value that is not there. Imagine we have a Map<Integer, String> that we need to get the key out of:
// creating and adding to the map
Map<Integer, String> myMap = new HashMap<>();
myMap.add(1, "Data at 1");
myMap.add(2, "Data at 2");
myMap.add(3, "Data at 3");
We can get String data from 1, 2, and 3 in the map:
myMap.get(1); // "Data at 1"
But what if we get it from 4?
myMap.get(4); // null
What’s so bad about that? Say we wanted to do something with the string we get back:
myMap.get(4).toUpperCase();
// Exception in thread "main" java.lang.NullPointerException
Whoops. We have to remember to check if the value is there
String result = myMap.get(4);
if (result != null) {
result = result.toUpperCase();
}
If we don’t check this here, code that depends on this operation now has to check for null. If that code doesn’t check, code above it needs to check and so on. It may seem innocuous at first but if we forget to check this kind of error propagates all the way through our programs.
Unchecked null is quite literally poisonous ☠️.
What can we do about it?
We still need the concept of a value not being there, but can we do it better?
Many typed functional languages treat the concept of absent values differently, as a specific example Elm does not have null . Instead it uses a special type called Maybe .
Maybe is defined as either Just a value, or Nothing : [1]
type Maybe a = Just a | Nothing
As an example, Elm has an equivalent Map type to Java called Dict (a key value store). Whenever we try to get values from a Dict the return type is always Maybe value (value being the type of whatever we’ve stored in the dict). The type system makes it explicit that any value fetched from a Dict might not be there, we are forced to deal with that possibility wherever we use that value.
One of Elm’s big selling points is that there are no runtime errors ever! (An extremely bold claim).
Java’s type system is easily capable of doing this too, and it’s now part of the language in Java 8:
Enter Optional<T>
We can have this same guarantee with Java’s Optional class. Whenever we have a value that we know might not be there we can “wrap” it in an Optional
public class OptionalExample {
private Map<Integer, String> myMap = new HashMap<>();
public OptionalExample() {
myMap.put(1, "Data at 1");
myMap.put(2, "Data at 2");
myMap.put(3, "Data at 3");
}
public Optional<String> getData(Integer i) {
return Optional.ofNullable(myMap.get(i));
}
}Now whenever we try to getData we have to handle an Optional<String>. But what about uppercasing the String? We can do this using Java 8’s new lambda syntax:
OptionalExample optionalMap = new OptionalExample();
optionalMap.getData(1).map(data -> data.toUpperCase());
// Optional<"DATA AT 1">
Using .map we can apply a transformation to the data if it’s present, and do nothing if it’s not there.
What about using that String somewhere else? When we finally want to extract the value we can use:
optionalMap
.get(1)
.map(data -> data.toUpperCase())
.orElse("Data not found");
Conclusion
This is only scratching the surface with whatOptional can do, check out the docs for the full range. Next time you come across null, why not try Optional.


Side Notes
[1] — Elm’s Maybe is most likely inspired by Haskell but Haskell has the concept of undefined which can throw runtime errors, although this is strongly discouraged.