Java 14 - Helpful NullPointerExceptions (JEP 358)
One of the feature in Java 14, JEP 358 – Helpful NullPointerExceptions aims to help developers to point-out the cause of a Null Pointer Exception.
As example, we have two classes Customer
and Address
:
package com.dariawan.jdk14.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Customer {
private Integer id;
private String name;
private Address address;
}
package com.dariawan.jdk14.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Address {
private String addressLine1;
private String addressLine2;
private String addressLine3;
private String zipCode;
}
Now let’s take a look at JEP358NullPointerExample01
, when the program try to access the value of cust.getAddress().getAddressLine1()
:
package com.dariawan.jdk14;
import com.dariawan.jdk14.dto.Customer;
public class JEP358NullPointerExample01 {
public static void main(String[] args) {
Customer cust = new Customer();
cust.setId(1);
cust.setName("Clark Kent");
System.out.println(cust);
System.out.println(cust.getAddress().getAddressLine1());
}
}
When running the program above, you will get following result:
$ java com.dariawan.jdk14.JEP358NullPointerExample01 Customer(id=1, name=Clark Kent, address=null) Exception in thread "main" java.lang.NullPointerException at com.dariawan.jdk14.JEP358NullPointerExample01.main(JEP358NullPointerExample01.java:51)
Java 14 try to help developer to understanding what causing NullPointerException
by showing precisely which variable was null:
$ java --enable-preview -XX:+ShowCodeDetailsInExceptionMessages com.dariawan.jdk14.JEP358NullPointerExample01 Customer(id=1, name=Clark Kent, address=null) Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.dariawan.jdk14.dto.Address.getAddressLine1()" because the return value of "com.dariawan.jdk14.dto.Customer.getAddress()" is null at com.dariawan.jdk14.JEP358NullPointerExample01.main(JEP358NullPointerExample01.java:51)
This feature is disabled by default, and can be enabled with the option: -XX:+ShowCodeDetailsInExceptionMessages
.
More Examples
Here some examples of the error messages before and after this feature is enabled:
package com.dariawan.jdk14;
import java.util.List;
public class JEP358NullPointerExample02 {
public static void main(String[] args) {
List<String> names = null;
System.out.print(names.size());
}
}
Before:
$ java com.dariawan.jdk14.JEP358NullPointerExample02 Exception in thread "main" java.lang.NullPointerException at com.dariawan.jdk14.JEP358NullPointerExample02.main(JEP358NullPointerExample02.java:47)
After:
$ java --enable-preview -XX:+ShowCodeDetailsInExceptionMessages com.dariawan.jdk14.JEP358NullPointerExample02 Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.List.size()" because "names" is null at com.dariawan.jdk14.JEP358NullPointerExample02.main(JEP358NullPointerExample02.java:47)
And following example is often happen when we compare two variables:
package com.dariawan.jdk14;
import java.util.HashMap;
import java.util.Map;
public class JEP358NullPointerExample03 {
public static void main(String[] args) {
Map<String, String> maps = new HashMap<>();
maps.put("key1", "value1");
String key = maps.get("key2"); // somehow is null
if (key.equals("key1")) {
System.out.print("key equals key1");
}
}
}
Of course, the comparison line is better if it re-written as if ("key1".equals(key"))
, regardless... here the result before:
$ java com.dariawan.jdk14.JEP358NullPointerExample03 Exception in thread "main" java.lang.NullPointerException at com.dariawan.jdk14.JEP358NullPointerExample03.main(JEP358NullPointerExample03.java:51)
And after:
$ java --enable-preview -XX:+ShowCodeDetailsInExceptionMessages com.dariawan.jdk14.JEP358NullPointerExample03 Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "key" is null at com.dariawan.jdk14.JEP358NullPointerExample03.main(JEP358NullPointerExample03.java:51)
Conclusion
From the three examples above, the error message before this enhancement is unclear, and need more tracing even guessing to get the exact culprit. JEP 358 bring a feature that can save developer's "precious" time to trace and understand why their program and logic is gone wrong.