90. Null Pointer Exceptions in Modern Java
Java 14+ shows exactly which variable was null in NPE messages; use Objects.requireNonNull, Optional, or @NonNull annotations to prevent NPEs early; avoid returning null from methods.
Explanation
Before Java 14, NullPointerException would just say "NullPointerException" with a stack trace pointing to the line โ unhelpful if the line had multiple dereferences. Since Java 14 (JEP 358), the JVM generates helpful NPE messages that identify exactly which variable was null: "Cannot invoke "String.length()" because "name" is null".
Prevention strategies: - Objects.requireNonNull(obj, "message"): validates constructor/method arguments; throws NPE with a clear message immediately. - Return Optional<T> instead of null from methods where absence is expected. - Avoid returning null from public methods โ use Optional or empty collections. - Use Objects.requireNonNullElse(value, default) for null-safe defaults. - Use null-safe utilities: Objects.toString(obj, "default"), Objects.isNull(obj). - Consider @NonNull / @Nullable annotations (from Checker Framework, JetBrains, etc.) for static analysis.
Example
import java.util.Objects;
import java.util.Optional;
public class NullPointerModern {
record User(String name, Address address) {}
record Address(String city, String country) {}
public static void main(String[] args) {
// Helpful NPE message (Java 14+): tells you WHAT was null
User user = new User("Alice", null); // address is null
try {
String city = user.address().city(); // NPE!
} catch (NullPointerException e) {
System.out.println("Helpful NPE: " + e.getMessage());
// Cannot invoke "Address.city()" because the return value of "User.address()" is null
}
// Objects.requireNonNull: fail-fast with clear message
try {
String name = null;
Objects.requireNonNull(name, "name must not be null");
} catch (NullPointerException e) {
System.out.println("requireNonNull: " + e.getMessage());
}
// Objects.requireNonNullElse: null-safe default
String maybeNull = null;
String safe = Objects.requireNonNullElse(maybeNull, "default");
System.out.println("Safe value: " + safe); // "default"
// Optional instead of null return
Optional<String> city = Optional.ofNullable(user.address())
.map(Address::city);
System.out.println("City: " + city.orElse("Unknown")); // Unknown
// Null-safe string
Object obj = null;
System.out.println(Objects.toString(obj, "null-safe")); // "null-safe"
// Constructor guard
class SafeService {
private final String url;
SafeService(String url) {
this.url = Objects.requireNonNull(url, "url must not be null");
}
}
try { new SafeService(null); }
catch (NullPointerException e) { System.out.println("Guard caught: " + e.getMessage()); }
}
}Sources
- https://openjdk.org/jeps/358 โ JEP 358: Helpful NullPointerExceptions (Java 14)
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Objects.html โ Objects utility class