Helpful NullPointerExceptions Information, from the JDK
2 min readIf you are using JDK 14 or above, please check out the NullPointerExceptions, where JDK providing more informative detail messages for an NPE. It is applaudable as it helps developers to identify the cause of the exception and fix the bug.
This feature was introduced as a JVM option in Java 14 and became the default behavior in Java 15.
Why is it helpful?
Think about a data model use case where user object has an address, in which has a city.
class UserDetails {
private String name;
private Address address;
}
class Address {
private String line1;
private String city;
private String state;
private String country;
}
Prior to JDK 14, if address does not exist where object called without a safe check, e.g. new UserDetails().getAddress().getLine1()
, a NullPointerException
is throw.
Exception in thread "main" java.lang.NullPointerException
at UserDetails.getAddress.getCity(UserDetails.java:6)
This message does not provide information about which part of the method call caused the NPE.
How is it different?
Comes in Java 14 is the introduction of "Helpful NullPointerExceptions”, and its establishment as the default behavior in Java 15: When an NPE is thrown, the JVM now provides a detailed message that includes information about which variable was null.
With Helpful NullPointerExceptions, the error message becomes more informative:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Address.getCity()" because "this.address" is null
at UserDetails.getCity(UserDetails.java:6)
This clearly indicates that the address field in the UserDetails object is null.
JVM composes the detailed exception message from two parts. The first part represents the failing operation, a consequence of a reference being null, while the second part identifies the reason for the null reference:
To build the exception message, JEP 358 recreates the part of the source code that pushed the null reference onto the operand stack.
As we can see, it marks a significant stride in Java's error handling and debugging capabilities, that allows less time-consuming when debugging. According to JEP 358, it only calculates the exception message when printed, not when the exception occurs. This makes it favorable as it avoids performance issues in normal JVM operations.
Some considerations
- The detailed exception message can include local variable names from the source code, posing a security risk. This happens only with code compiled with the
-g
flag, which adds debug information to the class file. - Detailed message computation in the JVM only happens for a NullPointerException thrown by the JVM itself, not for exceptions thrown manually in Java code. In manual cases, we usually add custom error messages in constructors already.