1. Introduction
Among the decisions we make as we're writing our applications, many are about when to throw exceptions and which type to throw.
In this quick tutorial, we're going to tackle the issue of which exception to throw when someone passes a null parameter to one of our methods: IllegalArgumentExcpetion or NullPointerException.
We'll explore the topic by examining the arguments for both sides.
2. IllegalArgumentException
First, let's look at the arguments for throwing an IllegalArgumentException.
Let's create a simple method that throws an IllegalArgumentException when passed a null:
public void processSomethingNotNull(Object myParameter) {
if (myParameter == null) {
throw new IllegalArgumentException("Parameter 'myParameter' cannot be null");
}
}
Now, let's move onto the arguments in favor of IllegalArgumentException.
2.1. It's How the Javadoc Says to Use It
When we read the Javadoc for IllegalArgumentException, it says it's for use when an illegal or inappropriate value is passed to a method. We can consider a null object to be illegal or inappropriate if our method isn't expecting it, and this would be an appropriate exception for us to throw.
2.2. It Matches Developer Expectations
Next, let's think about how we, as developers, think when we see stack traces in our applications. A very common scenario in which we receive a NullPointerException is when we've accidentally tried to access a null object. In this case, we're going to go as deep into the stack as we can to see what we're referencing that's null.
When we get an IllegalArgumentException, we are likely to assume that we're passing something wrong to a method. In this case, we'll look in the stack for the bottom-most method we're calling and start our debugging from there. If we consider this way of thinking, the IllegalArgumentException is going to get us into our stack closer to where the mistake is being made.
2.3. Other Arguments
Before we move onto the arguments for NullPointerException, let's look at a couple of smaller points in favor of IllegalArgumentException. Some developers feel that only the JDK should be throwing NullPointerException. As we'll see in the next section, the Javadoc doesn't support this theory. Another argument is that it's more consistent to use IllegalArgumentException since that's what we'd use for other illegal parameter values.
3. NullPointerException
Next, let's consider the arguments for NullPointerException.
Let's create an example that throws a NullPointerException:
public void processSomethingElseNotNull(Object myParameter) {
if (myParameter == null) {
throw new NullPointerException("Parameter 'myParameter' cannot be null");
}
}
3.1. It's How the Javadoc Says to Use It
According to the Javadoc for NullPointerException, NullPointerException is meant to be used for attempting to use null where an object is required. If our method parameter isn't intended to be null, then we could reasonably consider this as an object being required and throw the NullPointerException.
3.2. It's Consistent with JDK APIs
Let's take a moment to think about many of the common JDK methods we call during development. Many of them throw a NullPointerException if we provide a null. Additionally, Objects.requireNonNull() throws a NullPointerException if we pass in null. According to the Objects documentation, it exists mostly for validating parameters.
In addition to JDK methods that throw NullPointerException, we can find other examples of specific exception types being thrown from methods in the Collections API. ArrayList.addAll(index, Collection) throws an IndexOutOfBoundsException if the index is outside of the list size and throws a NullPointerException if the collection is null. These are two very specific exception types rather than the more generic IllegalArgumentException.
We could consider IllegalArgumentException to be meant for cases when we don't have a more specific exception type available to us.
4. Conclusion
As we've seen in this tutorial, this is a question that doesn't have a clear answer. The documentation for the two exceptions seems to overlap in that when taken alone, they both sound appropriate. There are also additional compelling arguments for both sides based on how developers do their debugging and on patterns seen in the JDK methods themselves.
Whichever exception we chose, we should be consistent throughout our application. Additionally, we can make our exceptions more useful by providing meaningful information to the exception constructor. For example, our applications will be easier to debug if we provide the parameter name in the exception message.
As always, the example code is available over on GitHub.