I have noted that many Java 8 methods in Oracle JDK use Objects.requireNonNull()
, which internally throws NullPointerException
if the given object (argument) is null
.
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
But NullPointerException
will be thrown anyway if a null
object is dereferenced. So, why should one do this extra null check and throw
NullPointerException
?
One obvious answer (or benefit) is that it makes code more readable and I agree. I'm keen to know any other reasons for using
Objects.requireNonNull()
in the beginning of the method.
Null pointer exception is thrown when you access a member of an object which is
null
at a later point.Objects.requireNonNull()
immediately checks the value and throws exception instantly without moving forward.Using
requireNonNull()
as first statements in a method allow to identify right now/fast the cause of the exception.The stacktrace indicates clearly that the exception was thrown as soon as the entry of the method because the caller didn't respect the requirements/contract. Passing a
null
object to another method may indeed provoke an exception at a time but the cause of the problem may be more complicated to understand as the exception will be thrown in a specific invocation on thenull
object that may be much further.Here is a concrete and real example that shows why we have to favor fail fast in general and more particularly using
Object.requireNonNull()
or any way to perform a no null check on parameters designed to be notnull
.Suppose a
Dictionary
class that composes aLookupService
and aList
ofString
representing words contained in. These fields are designed to be notnull
and one of these is passed in theDictionary
constructor.Now suppose a "bad" implementation of
Dictionary
withoutnull
check in the method entry (here that is the constructor):Now, let's invoke the
Dictionary
constructor with anull
reference for thewords
parameter :The JVM throws the NPE at this statement :
The exception is triggered in the
LookupService
class while the origin of it is well earlier (theDictionary
constructor). It makes the overall issue analysis much less obvious.Is
words
null
? Iswords.get(0) null
? Both ? Why the one, the other or maybe both arenull
? Is it a coding error inDictionary
(constructor? invoked method?) ? Is it a coding error inLookupService
? (constructor? invoked method?) ?Finally, we will have to inspect more code to find the error origin and in a more complex class maybe even use a debugger to understand more easily what it happened.
But why a simple thing (a lack of null check) become a complex issue ?
Because we allowed the initial bug/lack identifiable on a specific component leak on lower components.
Imagine that
LookupService
was not a local service but a remote service or a third party library with few debugging information or imagine that you didn't have 2 layers but 4 or 5 layers of object invocations before that thenull
be detected ? The problem would be still more complex to analyse.So the way to favor is :
In this way, no headache : we get the exception thrown as soon as this is received :
Note that here I illustrated the issue with a constructor but a method invocation could have the same non null check constraint.
As a side note, this fail fast before
Object#requireNotNull
was implemented slightly different before java-9 inside some of the jre classes themselves. Suppose the case :In java-8 this compiles as (only the relevant parts)
Basically an operation as :
yourReference.getClass
- which would fail if yourRefercence isnull
.Things have changed in jdk-9 where the same code compiles as
Or basically
Objects.requireNotNull (yourReference)
It means you detect the problem immediately and reliably.
Consider:
.NET makes this better by separating
NullReferenceException
("you dereferenced a null value") fromArgumentNullException
("you shouldn't have passed in null as an argument - and it was for this parameter). I wish Java did the same thing, but even with just aNullPointerException
, it's still much easier to fix code if the error is thrown at the earliest point at which it can be detected.Fail-fast
The code should crash as soon as possible. It should not do half of the work and then dereference the null and crash only then leaving half of some work done causing the system to be in an invalid state.
This is commonly called "fail early" or "fail-fast".
Because you can make things explicit by doing so. Like:
Or shorter:
Now you know:
new()
Compare that to: you create a Foo object today, and tomorrow you invoke a method that uses that field and throws. Most likely, you will not know tomorrow why that reference was null yesterday when it got passed to the constructor!
In other words: by explicitly using this method to check incoming references you can control the point in time when the exception will be thrown. And most of the time, you want to fail as fast as possible!
The major advantages are:
bar
isn't null - and thus you do not need anyif (bar == null)
checks in other places!