Как избежать NullPointerException
Короткий ответ
NullPointerException возникает, когда вы вызываете метод или берёте поле у ссылки, равной null. Сообщение подсказывает, что именно было null:
String findCity(String user) {
return user.equals("anna") ? "Berlin" : null;
}
void main() {
String city = findCity("oleg");
IO.println(city.toUpperCase());
}Результат:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because "<local1>" is nullПри запуске одного файла имена локальных переменных в сообщении заменяются на <local1> и похожие. В проекте, собранном с отладочной информацией, там будет "city".
Проверка на null
Самый прямой способ — проверить значение перед использованием:
void main() {
String city = null;
if (city != null) {
IO.println(city.toUpperCase());
} else {
IO.println("City unknown");
}
}Результат:
City unknownЗначение по умолчанию
Objects.requireNonNullElse() подставляет запасное значение вместо null:
void main() {
String nickname = null;
IO.println("Hello, " + Objects.requireNonNullElse(nickname, "guest"));
}Результат:
Hello, guestOptional
Если метод может ничего не найти, пусть он возвращает Optional — тогда вызывающий код явно обрабатывает пустой результат:
Optional<String> findCity(String user) {
return user.equals("anna") ? Optional.of("Berlin") : Optional.empty();
}
void main() {
IO.println(findCity("anna").map(String::toUpperCase).orElse("unknown"));
IO.println(findCity("oleg").map(String::toUpperCase).orElse("unknown"));
}Результат:
BERLIN
unknownРанняя проверка аргументов
Objects.requireNonNull() выбрасывает исключение сразу, с понятным сообщением, а не где-то глубоко в коде:
record User(String name) {
User {
Objects.requireNonNull(name, "name must not be null");
}
}
void main() {
new User(null);
}Результат:
Exception in thread "main" java.lang.NullPointerException: name must not be nullЧастая ошибка
Распаковка null в примитив. Это тоже NullPointerException, хотя метод явно не вызывается:
void main() {
Map<String, Integer> stock = new HashMap<>();
int count = stock.get("tea");
}Результат:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is nullИспользуйте getOrDefault("tea", 0) или храните результат в Integer и проверяйте его.
Функции из этого ответа
- Optional.ofNullable() — Оборачивает значение, которое может быть `null`, в `Optional`.
- Optional.orElse() — Возвращает значение или запасной вариант, если значения нет.
- Objects.requireNonNull() — Проверяет, что значение не null, и сразу бросает NullPointerException с понятным сообщением.