Mind the context of the null pointers

Photo by Raquel Pedrotti on Unsplash

A lot of Java developers seem to have an almost superstitious attitude towards the NullPointerException. Some of them seem to wish that the Java programming language forbade null pointers altogether.

Eliminating or at least reducing the incidence of null pointers was a major concern in the design of both Scala and Kotlin (two programming languages for the Java Virtual Machine).

More important than the occurrence of a NullPointerException is when and where it occurs. In development, it can point up a silly and easily fixed mistake. In production, it might be cause to fire someone.

Of course it’s scary to think that a NullPointerException could get you fired. But with test-driven development and robust quality assurance, you can be confident that the dreaded NullPointerException will only occur in development, not production.

Here’s a toy example to illustrate: bank accounts. Consider the following abstract class:

I was going to use this to illustrate how to use abstract classes to avoid unnecessary duplication of common functionality among similar classes. But since that’s not relevant for this example, I’ve left out the duplication.

Here’s the concrete class CheckingAccount:

As you can already see, there are three fields that can be null for a checking account: the field for the secondary account holder, the field for the beneficiary, and the field for the associated savings account.

But that’s actually not what’s going to get us into trouble when we run the tests for CheckingAccount.

The exception message “null” is useless. The stack trace, on the other hand, very helpfully points us to the problem in BankAccount.processDeposit():

What happened here was that this procedure attempted to add a Deposit object to accountHistory before accountHistory was even initialized. So the actual problem is in the constructor. The fix is easy:

We just have the constructor initialize accountHistory and then process the initial deposit. Now we can run the tests and get back to work on the actual logic of the program.

And so on and so forth. I have a GitHub repository for the source and tests of this toy example.

I emphasize that this is a toy example. You could make this sort of mistake, but if it happens this early in the process, the problem would surely be detected long before going to production, even without automated testing.

It’s more worrisome to make this sort of silly mistake in a more evolved project. What if the problem lurks in an obscure corner of the system?

This is part of the reason why good test coverage is important. If every line in which a NullPointerException could theoretically arise is covered by a test, and all the tests are running and passing, then you don’t have to worry that an unexpected NullPointerException could occur in production.

In general this applies to all exceptions. It’s just that NullPointerException is the exception that seems to occur the most often, and for the widest variety of error patterns, according to our own Andras Horvath.

I hope this helps you get a perspective on the NullPointerException as a useful debugging tool rather than something to dread.

is a composer and photographer from Detroit, Michigan. He has been working on a Java program to display certain mathematical diagrams.