5 проверенных способов защиты от NullPointerException в Java

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Для начинающих Java-разработчиков
  • Для опытных разработчиков, желающих улучшить качество своего кода
  • Для технических лидеров и менеджеров проектов в области программирования

    Работа со строками — хлеб с маслом программирования на Java, и недостаточное внимание к проверке на null или пустоту может привести к неприятным NullPointerException. Приходилось ли вам видеть, как падает продакшн только потому, что где-то в коде разработчик забыл проверить строку перед вызовом метода? 💥 Я расскажу о пяти проверенных способах обезопасить ваш код от таких ситуаций, подробно разберу каждый метод и поделюсь практическими рекомендациями, когда какой подход использовать.

Столкнулись с проблемами при работе со строками в Java? На Курсе Java-разработки от Skypro вы не только освоите надёжные методы проверки строк на null и пустоту, но и получите комплексное понимание работы с данными. Наши студенты уже на второй неделе обучения перестают допускать ошибки, связанные с NullPointerException, благодаря детальному разбору кодовых паттернов и практике с реальными задачами под руководством действующих разработчиков.

Почему важна проверка строк на null и пустоту в Java

Проверка строк на null и пустоту — это не просто хорошая практика, а необходимость для создания надежного и устойчивого к ошибкам кода. Java, будучи строго типизированным языком, не прощает небрежности при работе с объектами, особенно со строками, которые повсеместно используются в большинстве приложений.

Отсутствие проверок может привести к нескольким серьезным проблемам:

  • NullPointerException — самое распространенное исключение в Java, возникающее при попытке вызвать метод или получить доступ к свойству null-объекта
  • Логические ошибки — когда пустая строка интерпретируется иначе, чем предполагалось в бизнес-логике
  • Проблемы с производительностью — излишние или неэффективные проверки могут замедлить работу приложения
  • Уязвимости безопасности — непроверенные входные данные могут привести к эксплойтам в веб-приложениях

Алексей Петров, ведущий Java-разработчик

Однажды мы запустили новую версию платежной системы, где я отвечал за модуль обработки платежей. В 3 часа ночи меня разбудил звонок — система упала. Оказалось, что в блоке обработки адреса доставки чека не была реализована проверка на null. Пользователь не указал email, сервис попытался вызвать метод trim() для null-объекта, и всё рухнуло.

Мы быстро исправили ошибку, добавив простую проверку:

Java
Скопировать код
if (email != null && !email.isEmpty()) {
emailService.sendReceipt(email.trim(), receipt);
}

После этого случая в нашей команде появилось правило: любая строка, приходящая извне, должна проходить двойную проверку — на null и на пустоту.

Тип ошибки Причина Последствия
NullPointerException Вызов метода у null-ссылки Крах приложения, прерывание работы пользователя
Логические ошибки Путаница между null и пустой строкой Неправильная бизнес-логика, трудно отслеживаемые баги
Ошибки при конкатенации Попытка объединения со строкой null Строка с текстом "null" вместо ожидаемого значения
Пошаговый план для смены профессии

Метод 1: Проверка строки через условный оператор if

Самый базовый и понятный способ проверки строк — использование условного оператора if с явной проверкой на null и пустоту. Этот метод понятен даже начинающим разработчикам и не требует знания специфичных методов Java API.

Стандартная проверка выглядит так:

Java
Скопировать код
if (str != null && !str.equals("")) {
// Безопасно работаем со строкой
}

Более компактный вариант с использованием метода equals из объекта-константы:

Java
Скопировать код
if (str != null && !"".equals(str)) {
// Безопасно работаем со строкой
}

Второй вариант имеет небольшое преимущество — он менее подвержен ошибкам, поскольку исключает случайную замену операторов сравнения (== вместо !=).

Преимущества метода:

  • Понятность — код читается практически как обычное предложение
  • Универсальность — работает во всех версиях Java
  • Гибкость — легко модифицируется для дополнительных условий

Недостатки:

  • Многословность — требует явного написания двух условий
  • Риск ошибок — можно случайно перепутать порядок проверок
  • Неоптимальность — при частом использовании создает повторяющийся код

Мария Соколова, технический лид

В нашей команде новичок допустил классическую ошибку, которая чуть не стоила нам контракта с крупным клиентом:

Java
Скопировать код
if (!str.equals("") && str != null) {
// Код, который никогда не выполнится при null
}

Логика проверки была нарушена — сначала проверялось равенство пустой строке, а потом уже null. Если str == null, то первое же условие вызывало NullPointerException.

Мы внедрили два важных правила: порядок проверок должен быть строго от null к другим условиям, а для повторяющихся проверок мы создали утилитный класс StringUtils с методами:

Java
Скопировать код
public static boolean isNullOrEmpty(String str) {
return str == null || str.isEmpty();
}

public static boolean isNotNullOrEmpty(String str) {
return !isNullOrEmpty(str);
}

Это позволило нам избегать подобных ошибок и существенно сократить код.

Метод 2: Использование String.isEmpty() для пустых строк

Метод isEmpty() был добавлен в Java 6 и предоставляет более элегантный способ проверки строки на пустоту. Он проверяет, имеет ли строка длину 0, но не решает проблему проверки на null.

Типичное использование выглядит так:

Java
Скопировать код
if (str != null && str.isEmpty()) {
// Строка существует, но пуста
}

if (str != null && !str.isEmpty()) {
// Строка существует и не пуста
}

Важно понимать, что isEmpty() возвращает true только для строк с нулевой длиной. Строки, содержащие только пробельные символы, не считаются пустыми.

Выражение Результат для str = null Результат для str = "" Результат для str = " " Результат для str = "abc"
str.isEmpty() NullPointerException true false false
str != null && str.isEmpty() false true false false
str == null str.isEmpty() true true false false

Преимущества метода:

  • Читаемость — метод имеет говорящее название
  • Эффективность — внутренняя реализация оптимизирована в JVM
  • Стандартность — часть официального API Java

Недостатки:

  • Не обрабатывает null — все еще требуется отдельная проверка
  • Не учитывает строки с пробелами — для этого потребуются дополнительные методы
  • Доступен только с Java 6 и выше

Для более сложных случаев, когда требуется проверить, содержит ли строка только пробелы, можно использовать комбинацию с методом trim():

Java
Скопировать код
if (str != null && str.trim().isEmpty()) {
// Строка пуста или содержит только пробельные символы
}

Начиная с Java 11, появился более удобный метод isBlank(), который делает именно это:

Java
Скопировать код
if (str != null && str.isBlank()) {
// Строка пуста или содержит только пробельные символы
}

Метод 3: Проверка через length() и длину строки

Альтернативный способ проверки строки на пустоту — использование метода length(), который возвращает количество символов в строке. Этот метод присутствует в Java с первых версий и активно используется для различных операций со строками.

Основной паттерн использования:

Java
Скопировать код
if (str != null && str.length() == 0) {
// Строка существует, но пуста
}

if (str != null && str.length() > 0) {
// Строка существует и не пуста
}

Важно помнить, что length() — это метод объекта String, а не свойство, поэтому требуются скобки. Это отличает его от массивов, где длина действительно является свойством (array.length без скобок).

С точки зрения производительности, использование length() и isEmpty() практически идентично. Фактически, isEmpty() в своей реализации просто проверяет, равна ли длина строки нулю:

Java
Скопировать код
public boolean isEmpty() {
return value.length == 0;
}

Выбор между length() и isEmpty() обычно основывается на читаемости кода и предпочтениях команды разработчиков.

  • Используйте length(), когда вам также нужно знать конкретную длину строки или сравнивать её с другими значениями, а не только проверять на пустоту
  • Используйте isEmpty() для более ясного выражения намерения проверить строку именно на пустоту

Метод length() также может быть полезен для более сложных условий:

Java
Скопировать код
// Проверка, что строка не null и имеет нужную длину
if (str != null && str.length() >= 5 && str.length() <= 10) {
// Строка имеет от 5 до 10 символов
}

// Проверка на короткие строки
if (str != null && str.length() < 3) {
// Строка слишком короткая
}

Метод 4: Надежные утилиты Objects.isNull() для Java-разработчиков

Начиная с Java 7, появился класс Objects, предоставляющий статические методы для операций с объектами, включая проверки на null. Этот класс предлагает более элегантный способ работы с потенциально пустыми ссылками.

Два основных метода для проверки на null:

Java
Скопировать код
// Проверка, что объект равен null
if (Objects.isNull(str)) {
// Строка null
}

// Проверка, что объект не равен null
if (Objects.nonNull(str)) {
// Строка не null
}

Хотя эти методы просто обертывают стандартные проверки (str == null и str != null соответственно), они повышают читаемость кода и обеспечивают единообразие проверок по всему приложению.

Для комплексной проверки строк на null и пустоту можно комбинировать эти методы с ранее рассмотренными:

Java
Скопировать код
if (Objects.nonNull(str) && !str.isEmpty()) {
// Строка не null и не пуста
}

Класс Objects также предлагает мощный метод requireNonNull(), который проверяет объект на null и выбрасывает исключение, если проверка не проходит:

Java
Скопировать код
// Проверка с выбросом стандартного исключения
String nonNullStr = Objects.requireNonNull(str);

// Проверка с пользовательским сообщением
String nonNullStr = Objects.requireNonNull(str, "Строка не должна быть null");

// Проверка с генерацией сообщения через лямбда (Java 8+)
String nonNullStr = Objects.requireNonNull(str, 
() -> "Строка " + id + " не найдена в системе");

Этот метод особенно полезен для проверки параметров методов, когда null является недопустимым значением.

Преимущества использования класса Objects:

  • Повышенная читаемость кода
  • Унифицированный способ проверок по всему приложению
  • Поддержка функциональных возможностей в новых версиях Java
  • Совместимость с паттернами функционального программирования

Единственный недостаток — класс Objects доступен только с Java 7, поэтому не может использоваться в проектах, требующих совместимости с более ранними версиями Java.

Для полноценной проверки строк, с учетом всех возможных случаев, рекомендуется создать свой утилитный класс:

Java
Скопировать код
public class StringUtils {
public static boolean isNullOrEmpty(String str) {
return Objects.isNull(str) || str.isEmpty();
}

public static boolean isNullOrBlank(String str) {
return Objects.isNull(str) || str.trim().isEmpty();
}

public static boolean hasText(String str) {
return Objects.nonNull(str) && !str.trim().isEmpty();
}
}

Такой класс позволит значительно упростить проверки строк во всем приложении и сделать код более читаемым:

Java
Скопировать код
if (StringUtils.isNullOrEmpty(username)) {
throw new ValidationException("Имя пользователя не может быть пустым");
}

if (StringUtils.hasText(description)) {
saveDescription(description.trim());
}

Проверка строк на null и пустоту — это фундаментальный навык для Java-разработчика, который спасает от непредвиденных ошибок и повышает стабильность кода. Выбирайте подход, подходящий вашему проекту, учитывая требования к читаемости и производительности. Создайте набор утилитных методов, которые соответствуют стилю вашей команды, и последовательно используйте их во всей кодовой базе. Помните: лучшие разработчики не те, кто пишет сложный код, а те, кто предотвращает непредвиденные ситуации, задолго до того, как они могут возникнуть.

Загрузка...