Pages

Wednesday, November 23, 2016

One dollar solution to avoid null pointer exception in Java

This post is all about the null pointer exception, which we usually counter in our everyday programming. Before diving into the nitty-gritty of null, I want to go into why I named my post the $1 solution to avoid the null pointer exception.
Tony Hoare invented the null reference, later admitting that it was a billion-dollar mistake. Rather than making the same mistake of a null dollar solution, it would be apt to title my post the $1 dollar solution.
Let's consider an example for the paid dollar:

T t = null;

What do we actually mean here? Is 'null' a type of T or its subtype? It is just as valid a piece of code as typing what's below way and expecting the compiler to work for us.

T t; // compiler compels me to assign, huh?
Now, the variable 't' is just a reference without any object. 'Null' just explicitly endorses that convention. Accessing any of the properties of 'T' would make the compiler spew the famous 'NullPointerException.'
I recently got to know about the various remedies offered to salvage this problem. Among them is a way introduced in Java 8. My views vary slightly from the principles introduced. I was expecting Oracle to come up with a Null-Safe operator, similar to the Ternary operator, but again, they messed up and made another instance similar to bloated JEE non-wisdom stack.
Rather than me ripping that apart, let's head straight to some examples. Consider three classes A, B, and C, with A having a collaborator B and B having C:

class A {
  private B b;

  public B getB() {
      return b;
   }

}

class B {
  private C c;

  public C getC() {
      return c;
   }

}

class C {
  private int count = 0;

  public int getCount() {
      return count++;
   }

}

The general null check would be:

if(null != getA() && null != getA().getB() && null != getA().getB().getC()) {
     LOGGER.debug("The count is ", getA().getB().getC().getCount())
}

But using a null-safe operator like the one we have in Groovy...

int times = getA() ?. getB() ?. getC() ?. getCount();

Elvis' operator goes even further in returning the default value if it's null,

int times = getA() ?. getB() ?. getC() ?. getCount() ?: 0

Isn't it simple and natural? But Java complicated their design by compelling us to wrap it with the Optional<> construct and relying on flatMap and streams, thereby fabricating and garnishing code more with angle brackets.

a.flatMap(A::getB).flatMap(B::getC).map(C::getCount).orElse(0)// internally using if?

A mix of flatMap and scope resolution operators make the code cluttered and unreadable. But in the interest of doing more that viciously attacking null pointer exceptions, I just want to consciously be aware of null checks and their consequences when coding.
In fact, I love the design of the Kotlin language — keeping their design simple and straight, admiring the KISS principle.
Now, what if I use Java and still want to find a cleaner way of doing? Of course, we use IntelliJ or Eclipse, we can customize them to work for us by using annotations provided by them. Below, we'll get into how to use them and customize their severity level.

Using Intellij

IntelliJ provides two annotations, @Nullable and @NotNull.
How and when do we use the above two annotations?
For Java primitives, sensible defaults should be returned as something akin to 0, false, StringUtils.Empty.
For non-primitives, the method should convey the possibility of returning null. For example:
@Nullable 
findEmployeeById(int EmployeeNo) // may return null if there are no employee with the number

@NotNull
getCoursesOffered() // returns list of courses offered by a university which can be never null.

The findEmployeeById method has to be annotated with @Nullable, and getCoursesOffered should be annotated with @NotNull. It means that IDEs will enforce checking for null when findEmployeeById is used, and the null check would be redundant for getCoursesOffered.
The below picture (click on the pictures to get the full view) shows how to make use of @Nullable and @NotNull for the first example that we looked at. Just annotate the method with the respective annotation, and you get to see the warnings/errors. Picture #3 shows how to customize the severity of the Nullable warning message.







Depending on the severity level we set, the compiler in IntelliJ can show us Warning or Error upon inspection, highlighting the syntax.
Once the respective null checks/redundant check is placed/removed, the IntelliJ warning messages start to fade off.

Using Eclipse
For programmers who use Eclipse and reluctant to deprecate it for some reasons, it also provides two annotations @Nullable and @NonNull. The below pictures shows how to make use of @Nullable and @NonNull in eclipse and hopefully it should be self-explanatory.







Note: Despite encapsulating the code with a null check, the warning messages in Eclipse would continue to remain undisciplined, not like IntelliJ, where it uses its own brain deciding to display the message. 
I hope this helps keep log files pretty and ease the work for operational engineers!