Null Pointer Exception and The Promise of Java Optional: Why It Fails

Y Paulus Kh
Life At Moka
Published in
4 min readNov 19, 2019
Photo by Kevin Ku on Unsplash

Java NullPointerException (NPE) is such a pain, as it doesn’t tell you anything and neither does the stack trace. Here is the thing, I would highly appreciate if JVM tells me which part of this line triggers NPE:

Long departmentLeaderId = person.getDepartment().getLeader().getId();

Well? Is it the person? Of the department? Or the leader? Unfortunately, it’s hard to tell since Exception thrown only tells you which line triggers NPE, after that you’re on your own. You’re lucky if this occurs in your local environment and you’re able to debug the code? NPE in a production environment? Good luck with that.

Anyway there’s no cure for this, since JEP 358: Helpful NullPointerExceptions has not been delivered yet, hopefully, it will in JDK 14 (fingers crossed).

Bringing us to the behavior I’d like to call overly pessimistic NPE checking. It’s a pattern of null checking every variable that is not explicitly initialized. This is how the code above is written using this pattern:

Long departmentLeaderId = null;
if (person != null && person.getDepartment() != null &&
person.getDepartment().getLeader() != null) {
departmentLeaderId = person.getDepartment().getLeader().getId();
}

Or this

Long departmentLeaderId = null;
if (person != null) {
Department department = person.getDepartment();
if (department != null) {
DepartmentLeader leader = department.getLeader();
if (leader != null) {
departmentLeaderId = leader.getId();
}
}
}
// urrggghhh

Suddenly my code is littered with a lot of nested and multiple conditions, solely used for null checking every variable. Just because my experience with NPE debugging is so terrible, it’s better to be dirty than sorry.

But it’s so ugly and hard to test as well. Writing unit test for code above is painstakingly tedious, your IDE will keep on telling you that your unit test hasn’t covered all of the condition (thanks Sonar!). Also, adding more complexity to your code is a bad idea, the default rule of Cognitive Complexity tells that it shall not be greater than 15 making null checking like above is unacceptable (again, THANKS SONAR!).

Sometimes I wonder, can Java add something like safe navigation? You know, something like this:

Long departmentLeaderId = person?.getDepartment()?.getLeader()?.getId() ?: null;

That code will navigate safely to get the id of department leader without worrying much about null checking.

But adding new operator in Java is something of a blue moon, it’s a rare sight. I’m highly pessimistic about implementing this in Java (although Groovy, a rather dynamic language on Java platform already has this feature).

Then I stumbled upon this article: Tired of Null Pointer Exceptions? Consider Using Java SE 8’s “Optional"!

Optional in a nutshell is a class that encapsulates the optional value of something. So instead of getting the value of variable directly, we use the variable with Optional, then we can navigate more safely.

This is how we get departmentLeaderId using Optional.

Long departmentLeaderId = Optional.of(person).map(Person::getDepartment).map(Department::getLeader).map(DepartmentLeader::getId).orElse(null);

Notice that we use method reference introduced in Java 8 as an integral part of this code. Instead of getting the value of the department directly from a person, we use the map features to get the Optional of the department.

End of story?

NO.

These are some reasons why I don’t find any Optional used by my colleagues.

  1. There’s a flaw in the code above, a flaw that might cause another NPE. Instead of using Optional.of, we should use Optional.ofNullable. The reason is Optional.of throws NPE if the parameter is null. So if person is null it will throw NPE. The reason why Java gives us both is I believe to avoid unwanted behavior caused by a variable that should not be null but because of Optional, it can be navigated safely. Well, if it’s not supposed to be null, I don’t bother using Optional at all.
  2. It clutters the code. Rather than cluttering the code with a bunch of if-else why not clutters it with a lot of Optional? Speaking of how ceremonial Java is, Optional is a cherry on top of verbosity cake. Again safe navigation operator is much-much easier to read.
  3. Having Optional encapsulating your variables distracts you. Instead of having a real variable type as a form of self-documented code, you get Optional instead. You need more time to digest the information embedded in the code because of this.
  4. It’s rather challenging to write. Learning about Lambda after years of non-functional programming in Java is not a piece of cake. Coding with Lambda efficiently is another story. Learning about map, flatMap, orElse, orElseGet and all of the features is not easy for some people. Put Optional on top of that then you will get a NO from your colleague.
  5. Have I said that it’s verbose and I rather have safe navigation instead?

Having said that, I use Optional rather often these days. While refactoring codes littered with if-else and ternary operator, I find that Optional, while verbose, really helpful especially in the unit testing area. Writing unit tests for if-else statements with multiple conditions is a long process and hard to maintain, having Optional is a nice fresh air to have.

Afterall I get it, it’s ceremonial, almost a boilerplate, but it’s nice to have. I see myself trying my best to integrate this feature into my codes. It has it’s own charm anyway.

But still, I’d rather have safe navigation instead.

--

--

Y Paulus Kh
Life At Moka

A programming enthusiast, currently working as software engineer for a growing startup. Interested in technology, programming, and cooking.