Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как избежать 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, guest

Optional

Если метод может ничего не найти, пусть он возвращает 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 с понятным сообщением.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.