Improved NullPointerException Handling in Java 14 (JEP 358)
The article explains how Java 14 introduces enhanced NullPointerException messages via JEP 358, showing traditional NPE problems, the new detailed exception output, required JVM flags, performance considerations, and potential security implications, with code examples illustrating the improvements.
Handling NullPointerException in Java has long been a source of frustration, often leading to hard‑to‑track bugs and performance penalties. With the release of Java 14, developers can take advantage of JEP 358, which provides more informative exception messages.
1. Traditional NullPointerException
When code uses chained method calls, a NullPointerException can be thrown without indicating which part of the chain is null. For example:
String city = employee.getDetailInfos().getRegistryAddress().getCity();If employee , getDetailInfos() , or getRegistryAddress() returns null , the JVM throws a generic NullPointerException , and the stack trace only shows the method, file name, and line number.
Identifying the exact null variable without a debugger is difficult.
2. Enhanced NullPointerException
In 2006 SAP added an enhanced NPE to its commercial JVM. The idea was proposed to the OpenJDK community in 2019, became a JEP, and was shipped with JDK 14.
JEP 358 aims to improve the readability of NullPointerException messages by describing which variable is null . It analyzes bytecode to pinpoint the offending variable or expression.
By default the detailed messages are disabled. To enable them, start the JVM with:
-XX:+ShowCodeDetailsInExceptionMessages2.1 Detailed Exception Information
When the flag is active, a sample exception looks like:
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "RegistryAddress.getCity()" because the return value of
"com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException$DetailInfos.getRegistryAddress()" is null
at com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException.main(HelpfulNullPointerException.java:10)The message tells exactly which method returned null , saving debugging time.
The message consists of two parts: the failed operation (the null result) and the reason (the null reference).
Cannot invoke "String.toLowerCase()" because the return value of "getEmailAddress()" is nullJEP 358 rewrites the bytecode that pushes a null reference onto the operand stack to generate these messages.
3. Technical Details
Detailed messages are only computed when the JVM itself throws a NullPointerException . If the exception is explicitly thrown in user code, the extra computation is skipped.
The computation is lazy: the detailed message is built only when Throwable.getMessage() is called, so there is no performance impact during normal execution.
Because the detailed message may include local variable names, it can expose implementation details. This only happens when the code is compiled with the -g flag (debug information). For example, with debug info:
Employee employee = null;
employee.getName();The exception prints:
"com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException$Employee.getName()" because "employee" is nullWithout debug info, the JVM prints a generic placeholder:
"com.developlee.java14.helpfulnullpointerexceptions.HelpfulNullPointerException$Employee.getName()" because "<local1>" is nullThus, while the enhanced NPE greatly aids debugging, developers should be aware of the potential information leakage when distributing debug‑enabled binaries.
Java 14 users can enable the feature and benefit from faster issue localization, reduced debugging time, and improved code reliability.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.