Helpful NullPointerExceptions in Java
Messages that name exactly which reference was null.
Messages that point
Since Java 15 (JEP 358, introduced in 14 behind a flag), NPE messages name the action that failed and the expression that was null, like: Cannot invoke "String.length()" because "name" is null. They're on by default; a flag is needed only to turn them off.
Read the clue
The log says: Cannot invoke "String.trim()" because "user.profile.nickname" is null. Which reference was null?
useruser.profileuser.profile.nickname
Show the answer
The "because" part names the expression whose value was null: user.profile.nickname. The JVM successfully read .profile from user and .nickname from the profile, so those were fine. If it says "the return value of "Customer.address()"", a method returned the null: look at why it did.
The action tells the story
The first half describes what the bytecode tried to do: Cannot invoke "String.length()" (a method call), Cannot read field "city", Cannot assign field "x" (p.x = 5), Cannot store to int array (arr[0] = 1). In a chain like order.customer().address(), you learn exactly which link broke.
Unboxing hides a call
int n = counts.get("missing"); throws an NPE although you never wrote a method call. Auto-unboxing secretly calls intValue(), and the message says so: Cannot invoke "java.lang.Integer.intValue()"... When you see that, look for a null Integer being turned into an int.
Map<String, Integer> counts = new HashMap<>();
int n = counts.get("missing"); // NPE!Not every null explodes
s is null. What does this print?
String s = null;
String t = "x" + s;
System.out.println(t + t.length());xnull5Throws NullPointerExceptionx1
Show the answer
xnull5. String concatenation turns null into the text "null", so t is "xnull", length 5. But s.length(), s.equals("x") or a switch (s) without case null would throw.
Local names need -g
Fields and methods always appear by name. Local variable names appear only if the class was compiled with debug info (javac -g); otherwise the message shows placeholders like <local4>. Most build tools include that info by default.
Hours saved
In production, the stack trace points to a line, and the helpful message points to the exact expression. That turns "add logging and redeploy to find out" into a two-minute fix, especially in long chains like order.getCustomer().getAddress().getCity().
Key takeaways
- Messages name the failed action and the null expression
- Chains like order.customer().address() show which link failed
- On by default since Java 15 — no flag needed
- Local names need -g debug info; otherwise shown as <local4>
JEP 358 was authored by Goetz Lindenmaier of SAP, a reminder that OpenJDK features come from many companies, not just Oracle.
Practice questions
A log shows: Cannot read field "city" because "order.customer.address" is null. Which reference was null?
- order.customer.address
- order
- order.customer
- city
Check your answer
order.customer.address. The "because" part names the expression whose value was null. order and order.customer were fine; the address was missing.
A log shows: Cannot invoke "Address.city()" because the return value of "Customer.address()" is null. What's the most useful conclusion?
- The customer object existed, but its address() method returned null
- The customer variable itself was null
- city() threw an exception internally
- Address has no city() method
Check your answer
The customer object existed, but its address() method returned null. "The return value of" tells you a method call produced the null. Look at why address() returned null, not at the customer variable.