kpozin
kpozin

Reputation: 26969

Why doesn't Java tell you which pointer is null?

I've always wondered why the JVM doesn't tell you which pointer (or more precisely, which variable) is null when a NullPointerException is thrown.

A line number isn't specific enough because the offending line can often contain numerous variables that could have caused the error.

Is there any compiler or JVM flag that would make these exception messages more useful?

Upvotes: 29

Views: 2555

Answers (7)

Alex - GlassEditor.com
Alex - GlassEditor.com

Reputation: 15537

Since Java 15 it finally does tell you! See this JEP: https://openjdk.java.net/jeps/358 (it was actually added in Java 14 but was disabled by default, it is now enabled by default in Java 15).

Upvotes: 2

Martlark
Martlark

Reputation: 14581

You can add a breakpoint on the null pointer exception in Eclipse when debugging to get the exact cause of the exception.

Upvotes: 0

Michael Donohue
Michael Donohue

Reputation: 11876

It's because the dereference always happens when there is no name available. The value is loaded onto the operand stack, and is then passed to one of the JRE opcodes that dereferences it. However, the operand stack does not have a name to associate with a null value. All it has is 'null'. With some clever runtime tracking code, a name can be derived, but that would add overhead with limited value.

Because of this, there is no JRE option that will turn on extra information for null pointer exceptions.

In this example, the reference is stored in local slot 1, which maps to a local variable name. But the dereference happens in the invokevirtual instruction, which only sees a 'null' value on the stack, and then throws an exception:

15 aload_1
16 invokevirtual #5 

Equally valid would be an array load followed by a dereference, but in this case there is no name to map to the 'null' value, just an index off of another value.

76 aload    5
78 iconst_0
79 aaload
80 invokevirtual #5

You can't allocate the names statically to each instruction either - this example produces a lot of bytecode, but you can see that the dereference instruction will receive either objA or objB, and you would need to track this dynamically to report the right one, as both variables flow to the same dereference instruction:

(myflag ? objA : objB).toString()

Upvotes: 52

This is unfortunately just the way Java works.

If this is "your" code then simply add snippets like

if (foo == null) {
  throw new NullPointerException("foo == null");
}

right after assigning foo. If foo is a parameter then check immediately at the start of the method body, and throw IllegalArgumentException instead.

This should help you clarify matters.

Upvotes: 0

Grant Wagner
Grant Wagner

Reputation: 25941

If

A line number isn't specific enough because the offending line can often contain numerous variables that could have caused the error.

then I suggest:

  1. Breaking up that line into more than one line and assign the possible NullPointerException-generating values to temporary variables.
  2. Use a debugger and step over each method call until you find the one causing the problem.

Upvotes: 0

rob
rob

Reputation: 6247

If you break the line into multiple lines instead of making several method calls on one line, or if you set a breakpoint on that line and step through the line with a debugger, you can figure out which reference is null pretty easily.

Upvotes: 0

Sam Harwell
Sam Harwell

Reputation: 99949

Once you JIT the code, it's just native pointer math, and if any pointer in the native code is null it throws the exception. It would have a devastating performance impact to reverse that assembly back to the original variable, and considering the JIT optimizes the generated code to varying levels, is often not even possible.

Upvotes: 12

Related Questions