Нужна ли проверка на null перед instanceof в Java?
Краткий ответ: проверка на null перед instanceof не нужна
В Java оператор instanceof спроектирован так, что он безопасно обрабатывает null. Если операнд слева равен null, то instanceof всегда возвращает false, и никакого исключения не возникает. Это зафиксировано в спецификации языка Java (JLS §15.20.2). Поэтому ваш второй вариант кода абсолютно корректен и является идиоматическим способом проверки типа.
Почему так сделано?
Разработчики Java намеренно добавили эту возможность, чтобы упростить код и избежать лишних проверок. В большинстве случаев, когда вы пишете:
if (obj instanceof String) {
// работаем с obj как со строкой
}
вы не только проверяете тип, но и защищаетесь от null. Это одна из причин, почему instanceof считается "ленивым" оператором — он не генерирует исключение при null.
Примеры и подводные камни
Рассмотрим несколько сценариев:
- Простая проверка:
Результат: "Не строка или null". Без исключения.Object obj = null; if (obj instanceof String) { System.out.println("Это строка"); } else { System.out.println("Не строка или null"); // Выполнится это } - Проверка с интерфейсом:
Аналогично — никаких проблем.Object obj = null; if (obj instanceof List) { System.out.println("Это список"); } // Всё безопасно, просто false - С наследованием:
Операторclass Animal {} class Dog extends Animal {} Object obj = null; if (obj instanceof Dog) { // false // не выполнится }instanceofработает одинаково для всех типов: классов, интерфейсов, массивов.
Когда всё же нужна дополнительная проверка?
Есть единственный случай, когда стоит подумать о null отдельно — если вам нужно различать null и "не тот тип". Например:
if (obj == null) {
System.out.println("Объект null");
} else if (obj instanceof String) {
System.out.println("Строка");
} else {
System.out.println("Другой тип");
}
Но это уже логика бизнес-требований, а не необходимость защиты от исключений.
Распространённое заблуждение
Некоторые разработчики, особенно пришедшие из других языков (например, C#), думают, что instanceof может выбросить NullPointerException. Это не так. Java-спецификация явно гарантирует безопасность. Более того, если вы пишете if (obj != null && obj instanceof String), то вторая проверка избыточна — компилятор может даже выдать предупреждение (в некоторых IDE).
Итог
Пишите код лаконично:
if (obj instanceof String str) {
System.out.println(str.length()); // Pattern matching в Java 16+
}
Или для старых версий:
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str.length());
}
Никаких лишних null-проверок. Это безопасно, читаемо и соответствует лучшим практикам Java.
Альтернативный взгляд: когда проверка на null всё же полезна
Хотя instanceof сам по себе безопасен, я рекомендую иногда оставлять явную проверку на null для ясности кода. Например, если вы пишете библиотеку или API, где поведение при null должно быть документировано и очевидно.
Рассмотрим такой случай:
public void process(Object obj) {
if (obj instanceof String) {
// Логика для строки
} else {
// Логика для других типов, включая null
}
}
Здесь null обрабатывается в блоке else, что может быть неочевидно для читателя. Если вы хотите явно указать, что null — это особый случай, лучше написать:
public void process(Object obj) {
if (obj == null) {
throw new IllegalArgumentException("obj не должен быть null");
}
if (obj instanceof String) {
// ...
}
}
Также есть ситуации, когда вы используете instanceof в цепочке условий и хотите избежать случайного попадания null в неправильную ветку. Например:
if (obj instanceof String) {
// ...
} else if (obj instanceof Integer) {
// ...
} else {
// Здесь может оказаться null
}
Если вы не хотите, чтобы null обрабатывался в последнем else, добавьте явную проверку в начале.
В целом, это вопрос стиля и контекста. Технически проверка не нужна, но для читаемости и явного документирования поведения она может быть оправдана.