Issue
I recently stumbled upon a way to cause a NullPointerException
in Java that I wasn't aware of.
I found if you have a method like private void f(long l)
and you call the function like
Long l = null;
f(l);
then the f(l)
like will throw a NullPointerException
due to auto-unboxing a null
object.
Note that auto-unboxing also occurs when the object is used in a math expression like x > 1
, -x
, x * 2
, etc. or even a more complex expression like (b ? x : 1) - 2
.
I also found explicit unboxing by casting can also cause a NullPointerException
, for example:
Long l = null;
long x = (long) l; // Throws NullPointerException
Up until now, I only assumed accessing a field (i.e., obj.x
) or calling a method (i.e., obj.foo()
) could cause NullPointerException
s in Java.
I tried experimenting to see if string concatenation with a null object or formatting functions like String.format()
with a null argument could cause a NullPointerException
, but my experiments didn't turn up anything (which might just mean I missed something).
I also found that casting to a superclass does not throw, for example:
A a = null;
Object o = (Object) a; // Does not throw
Are there any other ways other than auto-unboxing a null object, explicit unboxing a null object with a cast, accessing a field on a null object, or calling a method no a null object that can cause a NullPointerException
?
I ask because I want to avoid getting lost (again) in the future trying to debug a problem like the invisible auto-unboxing that I wasn't aware could cause a NullPointerException
.
Solution
I think answering this question fully, on the level of the Java Programming Language is a bit too broad - there are way too many Java language features and too many built-in methods that can throw NPEs (if you count each one of them as a "different way") to consider.
I'll simplify the problem by considering all the Java Virtual Machine's instructions, and assume that you understand how the Java Programming Language is implemented in the Java Virtual Machine's instructions.
The list of instructions can be found here. By doing a text search for NullPointerException
, and I summarised it into a table:
Instructions | Descriptions | Example Java Code (not exhaustive) |
---|---|---|
xaload , xastore , arraylength |
Accessing a null array's contents or its length | array[0] , array[0] = 1; , array[0]++ array.length |
athrow |
throwing an exception that is null, or NullPointerException itself |
throw null; , throw new NullPointerException(); |
getfield , putfield |
accessing an instance field of a null reference | someObject.someField , someObject.someField = 2; |
invokeinterface , invokevirtual , invokespecial |
calling an instance method on a null reference | someObject.someMethod() |
monitorenter , monitorexit |
synchronising on null | synchronized(somethingNull) { ... } |
The unboxing case here is actually just a case of the invokevirtual
instruction invoking longValue
on a null reference, because that is how unboxing is specified.
I've also looked at the Java Language Specification to see what it says directly about NullPointerException
s, paraphrased in a more understandable-to-the-layperson way here (things already mentioned in the above table are omitted):
- Any integer/floating point operator can throw a
NullPointerException
if one of its operands is a boxed null reference - An unboxing conversion throws a
NullPointerException
if the boxed value is null. - Calling
super
on a null reference throws aNullPointerException
. If you are confused, this is talking about qualified superclass constructor invocations:
class Outer {
class Inner {}
}
class ChildOfInner extends Outer.Inner {
ChildOfInner(Outer o) {
o.super(); // if o is null, NPE gets thrown
}
}
Using a
for (element : iterable)
loop to loop through a null collection/array.switch (foo) { ... }
(whether its an expression or statement) can throw aNullPointerException
whenfoo
is null.foo.new SomeInnerClass()
throws aNullPointerException
whenfoo
is null.Method references of the form
name1::name2
orprimaryExpression::name
throws aNullPointerException
when evaluated whenname1
orprimaryExpression
evaluates to null.a note from the JLS here says that,
someInstance.someStaticMethod()
doesn't throw an NPE, becausesomeStaticMethod
is static, butsomeInstance::someStaticMethod
still throw an NPE!
The JLS probably also says a lot NPEs indirectly, but that will probably make this answer look more like a book.
Answered By - Sweeper
Answer Checked By - Cary Denson (JavaFixing Admin)