The most sure way to avoid a NullPointerException is to check all object references to ensure that they are not null before accessing one of the object's fields or methods. As the following example indicates, this is a very simple technique.

final String causeStr = "adding String to Deque that is set to null.";final String elementStr = "Fudd";Deque<String> deque = null;

In the code above, the Deque used is intentionally initialized to null to facilitate the example. The code in the first try block does not check for null before trying to access a Deque method. The code in the second try block does check for null and instantiates an implementation of the Deque (LinkedList) if it is null. The output from both examples looks like this:

ERROR: NullPointerException encountered while trying to adding String to Deque that is set to null.java.lang.NullPointerExceptionINFO: Successful at adding String to Deque that is set to null. (by checking first for null and instantiating Deque implementation)

The message following ERROR in the output above indicates that a NullPointerException is thrown when a method call is attempted on the null Deque. The message following INFO in the output above indicates that by checking Deque for null first and then instantiating a new implementation for it when it is null, the exception was avoided altogether.

Because checking null for every object reference can be tedious and does bloat the code, many developers choose to judiciously select which objects to check for null. This typically leads to checking of null on all objects of potentially unknown origins. The idea here is that objects can be checked at exposed interfaces and then be assumed to be safe after the initial check.

This is a situation where the ternary operator can be particularly useful. Instead of

The technique just discussed can be used on all objects. As stated in that technique's description, many developers choose to only check objects for null when they come from "untrusted" sources. This often means testing for null first thing in methods exposed to external callers. For example, in a particular class, the developer might choose to check for null on all objects passed to public methods, but not check for null in private methods.

The following code demonstrates this checking for null on method entry. It includes a single method as the demonstrative method that turns around and calls two methods, passing each method a single null argument. One of the methods receiving a null argument checks that argument for null first, but the other just assumes the passed-in parameter is not null.

ERROR: NullPointerException encountered while trying to provide null to method as argument.java.lang.NullPointerExceptionERROR: IllegalArgumentException encountered while trying to provide null to method as argument.java.lang.IllegalArgumentException: The provided StringBuilder was null; non-null value must be provided.

In both cases, an error message was logged. However, the case in which a null was checked for threw an advertised IllegalArgumentException that included additional context information about when the null was encountered. Alternatively, this null parameter could have been handled in a variety of ways. For the case in which a null parameter was not handled, there were no options for how to handle it. Many people prefer to throw a NullPolinterException with the additional context information when a null is explicitly discovered (see Item #60 in the Second Edition of Effective Java or Item #42 in First Edition), but I have a slight preference for IllegalArgumentException when it is explicitly a method argument that is null because I think the very exception adds context details and it is easy to include "null" in the subject.

The technique of checking method arguments for null is really a subset of the more general technique of checking all objects for null. However, as outlined above, arguments to publicly exposed methods are often the least trusted in an application and so checking them may be more important than checking the average object for null.

Checking method parameters for null is also a subset of the more general practice of checking method parameters for general validity as discussed in Item #38 of the Second Edition of Effective Java (Item 23 in First Edition).

Consider Primitives Rather than Objects

I don't think it is a good idea to select a primitive data type (such as int) over its corresponding object reference type (such as Integer) simply to avoid the possibility of a NullPointerException, but there is no denying that one of the advantages of primitive types is that they do not lead to NullPointerExceptions. However, primitives still must be checked for validity (a month cannot be a negative integer) and so this benefit may be small. On the other hand, primitives cannot be used in Java Collections and there are times one wants the ability to set a value to null.

The most important thing is to be very cautious about the combination of primitives, reference types, and autoboxing. There is a warning in Effective Java (Second Edition, Item #49) regarding the dangers, including throwing of NullPointerException, related to careless mixing of primitive and reference types.

Carefully Consider Chained Method Calls

A NullPointerException can be very easy to find because a line number will state where it occurred. For example, a stack trace might look like that shown next:

java.lang.NullPointerException at dustin.examples.AvoidingNullPointerExamples.demonstrateNullPointerExceptionStackTrace(AvoidingNullPointerExamples.java:222) at dustin.examples.AvoidingNullPointerExamples.main(AvoidingNullPointerExamples.java:247)

The stack trace makes it obvious that the NullPointerException was thrown as a result of code executed on line 222 of AvoidingNullPointerExamples.java. Even with the line number provided, it can still be difficult to narrow down which object is null if there are multiple objects with methods or fields accessed on the same line.

For example, a statement like someObject.getObjectA().getObjectB().getObjectC().toString(); has four possible calls that might have thrown the NullPointerException attributed to the same line of code. Using a debugger can help with this, but there may be situations when it is preferable to simply break the above code up so that each call is performed on a separate line. This allows the line number contained in a stack trace to easily indicate which exact call was the problem. Furthermore, it facilitates explicit checking each object for null. However, on the downside, breaking up the code increases the line of code count (to some that's a positive!) and may not always be desirable, especially if one is certain none of the methods in question will ever be null.

Make NullPointerExceptions More Informative

In the above recommendation, the warning was to consider carefully use of method call chaining primarily because it made having the line number in the stack trace for a NullPointerException less helpful than it otherwise might be. However, the line number is only shown in a stack trace when the code was compiled with the debug flag turned on. If it was compiled without debug, the stack trace looks like that shown next:

As the above output demonstrates, there is a method name, but not no line number for the NullPointerException. This makes it more difficult to immediately identify what in the code led to the exception. One way to address this is to provide context information in any thrown NullPointerException. This idea was demonstrated earlier when a NullPointerException was caught and re-thrown with additional context information as a IllegalArgumentException. However, even if the exception is simply re-thrown as another NullPointerException with context information, it is still helpful. The context information helps the person debugging the code to more quickly identify the true cause of the problem.

ERROR: NullPointerException encountered while trying to NullPointerException with useful datajava.lang.NullPointerExceptionERROR: NullPointerException encountered while trying to NullPointerException with useful datajava.lang.NullPointerException: Could not extract Date from provided Calendar

The first error does not provide any context information and only conveys that it is a NullPointerException. The second error, however, had explicit context information added to it which would go a long way in helping identify the source of the exception.

Use String.valueOf Rather than toString

As described previously, one of the surest methods for avoiding NullPointerException is to check the object being referenced for null first. The String.valueOf(Object) method is a good example of a case where this check for null can be done implicitly without any additional effort on the developer's part. I blogged on this previously, but include a brief example of its use here.

This example demonstrates that use of String.valueOf(Object) enables the attempt to get the null BigDecimal's String representation be provided with a "null" string rather than a NullPointerException being thrown. This can be a particularly useful technique for implementing objects' toString() implementations.

One minor downside of use of String.valueOf stems from its behavior that is normally a positive. Although there are many cases where having a null object's String representation be returned as a "null" String is better than having a NullPointerException thrown, this can sometimes be a disadvantage if used indiscriminately. For example, String methods called on the String returned by valueOf(Object) will return a real String with the characters null. This is proven by the following code.

The code above leads to these results that prove that there is a String "null" returned by String.valueOf(Object) when it is called upon an object with a null reference.

INFO: The length of the nullString is 4INFO: String is NOT empty.

As the code and results above show, use String.valueOf(Object) on a null object will actually return a non-empty String (four characters n-u-l-l).

Avoid Returning Nulls

In Item #43 of the Second Edition of Effective Java (Item #27 in the First Edition), Joshua Bloch recommends returning empty arrays or empty collections rather than returning null. He points out that returning null requires client code to make special effort to handle such a contingency. When a client fails to do so, a NullPointerException is almost certainly going to be encountered down the road. The Java Collections class has useful methods for returning empty Collections that make it really easy to follow this advice. I have often found it to be similarly useful to return empty Strings rather than null for methods returning a String to indicate no match or error condition.

While there are problems associated with returning a null to indicate a failure or less than successful status, returning a null to indicate success is even more troubling because it is not normally associated with a positive outcome. In other words, it is typically not a good idea to return null as an indicator of success and a non-null object as an indicator of some type of failure.

I previously mentioned the importance of checking passed-in parameters for null. There are several steps one can take to reduce the chance of nulls being passed into constructors or methods in the first place. One easy approach is to specify in the Javadoc comments on the method or constructor which arguments must not be null. This is appropriately documented in the @param tags. Similarly, if an exception is thrown when a null parameter is encountered, that exception can be advertised in the Javadoc comment with the @throws tag.

Some Java Strings are more likely to be non-null than others. For example, literal Strings are obviously not null. String constants and other Strings with well-known sources are also more trusted to be non-null. When comparing two Strings for equality with the equals method (or the equalsIgnoreCase method), it is typically best to call the equals method on the String that is more likely to NOT be null. This reduces the chances of a NullPointerException.

The following example code compares the two approaches, trying to access equals on a String that is really null and on a non-null String. The results are very different.

ERROR: NullPointerException encountered while trying to call 'equals' on null Stringjava.lang.NullPointerExceptionINFO: null is NOT equal to Sally Ann Cavanaugh

When the equals method was invoked on a null, the only text message we were presented with was the name of the exception. By invoking the equals method against a safe, non-null String, we avoid the exception altogether and got a correct result (the null passed to the equals method does not match the String on which the equals method is invoked).

Let Others Do the Heavy Lifting

As mentioned before, one of the safest ways to avoid the NullPointerException is to add code to check each object for null before accessing its methods and attributes. It is really nice when this check can be done without any extra effort. The String.valueOf(Object) method covered earlier does this for calling toString() on potentially null references. There are other libraries that provide similar built-in null-checking support so that you don't need to explicitly check for null. An example is ToStringBuilder, which builds toString() representations of objects and gracefully handles any null references in the object.

/** * Demonstrate how supplying context information to an * {@link NullPointerException} can make it more useful for clients and for * debugging. */ public void demonstrateThrowingMoreUsefulNullPointerException() { logHeader("CONSTRUCT NULLPOINTEREXCEPTION WITH USEFUL DATA", System.out); final Calendar nullCalendar = null;

/** * Demonstrates that while String.valueOf(String) does perform like a * {@code toString()} call without the risk of a {@code NullPointerException}, * it also has the side effects of returning a non-null, non-empty String * (four characters) for an object that is actually null. This is because * it returns "null". */ public void demonstratingSideEffectsOfStringValueOf() { logHeader("SIDE EFFECTS OF STRING.VALUEOF(OBJECT)", System.out); final String nullString = null; final String nullStringValueOf = String.valueOf(nullString); log("The length of the nullString is " + nullStringValueOf.length(), System.out); if (nullStringValueOf.isEmpty()) { log("Empty String!", System.out); } else { log("String is NOT empty.", System.out); } }

/** * Demonstrate a {@code NullPointerException} stack trace. To see the * difference between debug and nodebug, compile this class both with debug * turned on and with debug turned off and run this method with each setting. * With debug on, line numbers will be included in the stack trace; these line * numbers will not be included with the nodebug mode */ public void demonstrateNullPointerExceptionStackTrace() { logHeader("EXAMPLE STACK TRACE FOR NULLPOINTERECEPTION", System.out); final Object nullObject = null; try { final String objectString = nullObject.toString(); } catch (NullPointerException nullPointer) { final PrintWriter writer = new PrintWriter(System.out); nullPointer.printStackTrace(writer); writer.close(); log("END OF NULL POINTER STACK TRACE", System.out); } }

The complete output when this code is run as shown above is shown next.

====================================================================ORDER IN STRING COMPARISON====================================================================ERROR: NullPointerException encountered while trying to call 'equals' on null Stringjava.lang.NullPointerExceptionINFO: null is NOT equal to Sally Ann Cavanaugh

====================================================================CONSTRUCT NULLPOINTEREXCEPTION WITH USEFUL DATA====================================================================ERROR: NullPointerException encountered while trying to NullPointerException with useful datajava.lang.NullPointerExceptionERROR: NullPointerException encountered while trying to NullPointerException with useful datajava.lang.NullPointerException: Could not extract Date from provided Calendar

====================================================================DEMONSTRATING CHECKING METHOD PARAMETERS FOR NULL====================================================================ERROR: NullPointerException encountered while trying to provide null to method as argument.java.lang.NullPointerExceptionERROR: IllegalArgumentException encountered while trying to provide null to method as argument.java.lang.IllegalArgumentException: The provided StringBuilder was null; non-null value must be provided.

====================================================================DEMONSTRATE CHECKING FOR NULL BEFORE ACTING====================================================================ERROR: NullPointerException encountered while trying to adding String to Deque that is set to null.java.lang.NullPointerExceptionINFO: Successful at adding String to Deque that is set to null. (by checking first for null and instantiating Deque implementation)

====================================================================USING STRING.VALUEOF RATHER THAN TOSTRING====================================================================ERROR: NullPointerException encountered while trying to getting BigDecimal as String representationjava.lang.NullPointerExceptionINFO: Retrieved null by getting BigDecimal as String representation

====================================================================SIDE EFFECTS OF STRING.VALUEOF(OBJECT)====================================================================INFO: The length of the nullString is 4INFO: String is NOT empty.

====================================================================EXAMPLE STACK TRACE FOR NULLPOINTERECEPTION====================================================================java.lang.NullPointerException at dustin.examples.AvoidingNullPointerExamples.demonstrateNullPointerExceptionStackTrace(AvoidingNullPointerExamples.java:239) at dustin.examples.AvoidingNullPointerExamples.main(AvoidingNullPointerExamples.java:265)

Conclusion

The NullPointerException can be very helpful in identifying problems in our applications and especially in identifying problems with many assumptions we often make when developing software. However, there are times when we encounter them without any benefit or new information simply because we have not taken proper steps to avoid them. This posting has attempted to cover techniques that are commonly used to reduce NullPointerException exposure, to make valid NullPointerExceptions more meaningful, and to handle NullPointerExceptions more gracefully. Use of these techniques can reduce the number of NullPointerExceptions encountered, increase the quality of those that are encountered, and improve out ability to identify the very problems that that remaining NullPointerExceptions are meant to convey.

7 comments:

IDEs can also help with catching potential nulls. For example, IntelliJ IDEA allows you to use annotations to actually add information to method & variable contracts about whether nulls are acceptable.

An interesting, related read is Sir Charles Antony Richard Hoare's presentation Null References: The Billion Dollar Mistake. The abstract for this presentation states, "I call it my billion-dollar mistake. It was the invention of the null reference in 1965. ... But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This 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."