null pointer handling in modern Java

Liu Tao
3 min readSep 2, 2019

--

Photo by Philipp Berndt on Unsplash

In traditional programming languages like Java or C++, null is a member of all reference type. It’s used to model that one value is either unknown or non-existent. Tony Hoare invented it in 1965 and now described it as a billing dollars mistake.

This led me to suggest that the null value is a member of every type, and a null check is required on every use of that reference variable, and it may be perhaps a billion dollar mistake.

For example, you defined a Person class and created a group of person objects. All of them have the same attribute and behavior. But secretly, the language injects null into this group. As showing in below diagram:

Person Class

To use any person object, you have to check whether that reference is null. This null-check adds a lot of unnecessary complexity in our code.

non-nullable references by default

Unnecessary null-check is a design error on the language side. That’s why in new languages like Kotlin, object reference is non-nullable by default.

var a: String = “hello”a = null; //won’t compile because a is non-nullable by default

User needs explicit declare the variable as nullable:

var a: String? = “hello”a = null; //compile ok

Option type for old language

For old languages like Java, it needs to maintain backward compatibility for the legacy code. So non-nullable reference by default is not a valid approach. Java 8 added Option type to make the possibly null value more explicit. That’s the most the language can provide to us. We still need static analysis tool and engineering discipline to prevent null pointer exception.

Best Practice about null pointer handling in Java

  • Use Option for output

The evil of null comes from its ambiguity. By returning Option from API, we explicitly tell the other party that the value could be missing. They have no chance to miss the necessary check on their side.

Lombok provides this annotation to generate null check automatically. Also, it can serve as documentation for the interface.

public class NonNullExample {private String name;

public NonNullExample(@NonNull Person person) {
this.name = person.getName();
}
}
  • Use constant literal for comparison:
input.equals("Hello"); // null pointer exception when input is null
"Hello".equals(input); // it's safe even input is null
  • Use null object pattern

Martin Fowler says Instead of returning null, or some odd value, return a Special Case that has the same interface as what the caller expects. This simplifies the logic on the caller-side. But we still need to tell the caller that no null value will be returned and they don’t need to do null-check. This can only be done during the contract negotiation with the caller.

--

--