Better NPE Messages in JDK 14
Learn more about Early Access Builds for JDK 14, specifically better NullPointerException messages.
Join the DZone community and get the full member experience.
Join For FreeMy March 2019 blog post "Better Default NullPointerException Messages Coming to Java?" was written when the draft JEP for better NullPointerException messages had not yet been targeted to a particular JDK release. Since then, that draft JEP became JEP 358 ("Helpful NullPointerExceptions"), which has been targeted for JDK 14. Even better, the initial implementation (JDK-8218628) is already in the JDK 14 branch and is available to play around with in JDK 14 Early Access Builds, Build 20 (2019/10/23).
In this post, I will run the example code introduced in my previous post against the JDK 14 Early Access Build 20 to demonstrate the additional details now provided. To see the example code that was written to intentionally introduce a variety of situations resulting in NullPointerException
s, check out that post or view the source code on GitHub.
You may also like: 10 Tips to Handle Null Effectively
With the JDK 14 Early Access Build 20 downloaded and pointed to by my path, I see the following when I run java -version
:
openjdk version "14-ea" 2020-03-17
OpenJDK Runtime Environment (build 14-ea+20-879)
OpenJDK 64-Bit Server VM (build 14-ea+20-879, mixed mode, sharing)
With the JDK 14 Early Access Build 20 configured appropriately, I rebuilt the source code mentioned previously and then re-ran the code with the Java launcher without any new options. The output from this (shown below) is not materially different from the output with previous JDK versions.
=========================================
| #1: Element [0] on null boolean array |
=========================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateFirstExampleIndexAccessOnNullBooleanArray(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=================================
| #2: .length on null boolean[] |
=================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateSecondExampleLengthOnNullBooleanArray(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=======================================
| #3: Assigning float to null float[] |
=======================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateThirdExampleAssigningValueToElementOfNullFloatArray(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
======================================
| #4: Accessing field on null object |
======================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateFourthExampleAccessInstanceFieldOfNullObject(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
===================
| #5: throw null; |
===================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateFifthExampleThrowingConstantNull(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
================================================
| #6: Method invocation on null instance field |
================================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateSixthExampleMethodInvocationOnNullInstanceField(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=============================================
| #7: synchronized() on null instance field |
=============================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateSeventhExampleSynchronizedNullInstanceField(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
==========================================================================
| >>> Null Lost in Long Series of Method Invocations in Single Statement |
==========================================================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateNullLostInSeriesOfMethodInvocationsInSingleStatement(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=======================================================
| >>> Null Lost in Dereferenced Constructor Arguments |
=======================================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateNullLostInConstructorAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
==================================================
| >>> Null Lost in Dereferenced Method Arguments |
==================================================
java.lang.NullPointerException
at dustin.examples.npe.NpeDemo.demonstrateNullLostInMethodAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
As the above output demonstrates, even with the new JDK 14 Early Access Build 20, I don't see any new detailed information regarding NullPointerException
s when I run my application as normal. I included this output to show that a special flag is needed to enable the more detailed NullPointerException
s and to make it more convenient to compare the output without and with the extra details. The next output listing shows the additional details provided when the Java launcher is passed the flag -XX:+ShowCodeDetailsInExceptionMessages
:
=========================================
| #1: Element [0] on null boolean array |
=========================================
java.lang.NullPointerException: Cannot load from byte/boolean array because "<local1>" is null
at dustin.examples.npe.NpeDemo.demonstrateFirstExampleIndexAccessOnNullBooleanArray(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=================================
| #2: .length on null boolean[] |
=================================
java.lang.NullPointerException: Cannot read the array length because "<local1>" is null
at dustin.examples.npe.NpeDemo.demonstrateSecondExampleLengthOnNullBooleanArray(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=======================================
| #3: Assigning float to null float[] |
=======================================
java.lang.NullPointerException: Cannot store to float array because "<local1>" is null
at dustin.examples.npe.NpeDemo.demonstrateThirdExampleAssigningValueToElementOfNullFloatArray(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
======================================
| #4: Accessing field on null object |
======================================
java.lang.NullPointerException: Cannot read field "nullInstanceField" because "<local1>" is null
at dustin.examples.npe.NpeDemo.demonstrateFourthExampleAccessInstanceFieldOfNullObject(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
===================
| #5: throw null; |
===================
java.lang.NullPointerException: Cannot throw exception because "null" is null
at dustin.examples.npe.NpeDemo.demonstrateFifthExampleThrowingConstantNull(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
================================================
| #6: Method invocation on null instance field |
================================================
java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "this.nullInstanceField" is null
at dustin.examples.npe.NpeDemo.demonstrateSixthExampleMethodInvocationOnNullInstanceField(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=============================================
| #7: synchronized() on null instance field |
=============================================
java.lang.NullPointerException: Cannot enter synchronized block because "this.nullInstanceField" is null
at dustin.examples.npe.NpeDemo.demonstrateSeventhExampleSynchronizedNullInstanceField(Unknown Source)
at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
==========================================================================
| >>> Null Lost in Long Series of Method Invocations in Single Statement |
==========================================================================
java.lang.NullPointerException: Cannot invoke "dustin.examples.npe.DysfunctionalLocation$Province.getCity()" because the return value of "dustin.examples.npe.DysfunctionalLocation$Nation.getProvince()" is null
at dustin.examples.npe.NpeDemo.demonstrateNullLostInSeriesOfMethodInvocationsInSingleStatement(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
=======================================================
| >>> Null Lost in Dereferenced Constructor Arguments |
=======================================================
java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because "<local6>" is null
at dustin.examples.npe.NpeDemo.demonstrateNullLostInConstructorAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
==================================================
| >>> Null Lost in Dereferenced Method Arguments |
==================================================
java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because "<local6>" is null
at dustin.examples.npe.NpeDemo.demonstrateNullLostInMethodAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
at dustin.examples.npe.NpeDemo.main(Unknown Source)
JEP 358 explains the use of this flag for seeing additional NullPointerException
details: "The feature can be toggled with the new boolean
command-line option -XX:{+|-}ShowCodeDetailsInExceptionMessages
. The option will first have default 'false
' so that the message is not printed. It is intended to enable code details in exception messages by default in a later release." As we see, this feature is initially turned off by default, but there is a plan to enable more detailed NullPointerException
messages in the future.
A recent Tweet asked the question: "How it will work if bytecode doesn’t contain variable names?"
The question continued by providing a specific example: "Suppose we have code like Object a = ....; a.getName(); //NPE
What kinds of message NPE would have?" Although an example of this is included in my battery of tests shown earlier, I thought I'd provide a more focused example here in response to that question. The next code listing (which is also available on GitHub) shows code adapted from the example used in the Tweet.
package dustin.examples.npe;
/**
* Simple demonstration to answer Tweet-ed question
* "How it will work if bytecode doesn't contain variable names?"
* (https://twitter.com/2doublewhiskey/status/1180365953240055809).
*/
public class TwoDoubleWhiskeyTweetExample
{
public static void main(final String[] arguments)
{
final Person person = null;
person.getName(); //NPE
}
public static class Person
{
private String name;
public Person(final String newName)
{
name = newName;
}
public String getName()
{
return name;
}
}
}
The next screen snapshot shows the result of running this simple application with the JDK 14 Early Access Build 20 without, and then with, the java
launcher flag -XX:+ShowCodeDetailsInExceptionMessages
.
As the screen snapshot indicates, using the -XX:+ShowCodeDetailsInExceptionMessages
flag with the JDK 14 Early Access Build 20 provides this additional detail related to this simple NullPointerException
example: "Cannot invoke "dustin.examples.npe.TwoDoubleWhiskeyTweetExample$Person.getName()" because "<local1>" is null"
An example that is simpler and even closer to the original example provided in the Tweet-ed question is available on GitHub.
JEP 358 ("Helpful NullPointerExceptions") may not be as flashy as some other JEPs that come to new JDK releases, but it may be one that in the end provides more value to Java developers on a daily basis than some of its flashier peers. There are numerous examples where this will be helpful, and many of those example situations are spelled out in the JEP itself, and in my code examples referenced in this post.
Further Reading
Published at DZone with permission of Dustin Marx, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments