Ответ
Начиная с Java 14, NullPointerException содержит подробную информацию о том, какой именно вызов вызвал исключение.
Эволюция фичи:
| Версия Java | Статус | Как включить |
|---|---|---|
| Java 14 | Предварительная просмотр (JEP 358) | -XX:+ShowCodeDetailsInExceptionMessages |
| Java 15 | Вторая предварительная просмотр (JEP 384) | -XX:+ShowCodeDetailsInExceptionMessages |
| Java 16 | Стандартная фича (JEP 396) | Включено по умолчанию |
| Java 17+ | Стабильная часть языка | Всегда включено |
Пример до улучшений:
public class Example {
public static void main(String[] args) {
User user = getUser(); // возвращает null
// Старый вывод: NullPointerException
System.out.println(user.getProfile().getName().toUpperCase());
}
}
Вывод: NullPointerException (без деталей)
Пример после улучшений:
public class Example {
public static void main(String[] args) {
User user = getUser(); // возвращает null
// Новый вывод с детализацией
System.out.println(user.getProfile().getName().toUpperCase());
}
}
Вывод в Java 16+:
NullPointerException: Cannot invoke "User.getProfile()" because the return value of "getUser()" is null
Другие примеры детализации:
// Случай 1: Поле объекта null
String text = null;
System.out.println(text.length());
// Output: Cannot invoke "String.length()" because "text" is null
// Случай 2: Элемент массива null
String[] array = {"a", null, "c"};
System.out.println(array[1].length());
// Output: Cannot invoke "String.length()" because "array[1]" is null
// Случай 3: Локальная переменная null
public void process(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
// Детализация всё равно работает
System.out.println(user.getName().toUpperCase());
}
Преимущества:
- Быстрая диагностика — сразу видно, какой вызов вызвал NPE
- Уменьшение времени отладки — не нужно анализировать stack trace построчно
- Улучшение читаемости логов — понятные сообщения даже для сложных цепочек вызовов
Ограничения:
- Не работает для
toString()неявных вызовов - Может не показывать детали в highly optimized коде (после JIT-компиляции)
- Незначительный overhead при создании исключения