Нужна ли нулевая проверка перед вызовом instanceof?

1354

Будет ли null instanceof SomeClassвернуться falseили бросить NullPointerException?

Йохан Любке
источник
Он также «важен» или, по крайней мере, очень полезен как начальная (или очень ранняя) строка «наилучшей практики» для любого метода сравнения или равенства или аналогичного метода, который предназначен для успешной работы только с ненулевыми объектами того же типа, и защищает вас от «глупых дел» в одну строку. меньше кода = меньше ошибок.
13
Чтобы взвесить "это полезно?" дискуссия - я никогда не писал свой собственный Java-код (поэтому не легко узнать, где спецификации, и компиляция теста была бы очень нетривиальной), но в настоящее время я вручную конвертирую Java в JavaScript. Мой код не выполнялся по нулевой ссылке, и поиск в Google позволил мне увидеть принятый ответ, который подтвердил, что это было ожидаемое поведение и что я пропускал неявную нулевую проверку. Очень полезно, в моем случае.
Скотт Мермельштейн

Ответы:

1841

Нет, проверка нуля не требуется перед использованием instanceof.

Выражение x instanceof SomeClassэто , falseесли xесть null.

Из спецификации языка Java, раздел 15.20.2, «Оператор сравнения типов instanceof» :

«Во время выполнения результат instanceofоператора - trueесли значение RelationalExpression отсутствует,null и ссылка может быть приведена к ReferenceType без повышения ClassCastException. В противном случае результат будет false».

Так что, если операнд равен нулю, результат ложен.

Энди Томас
источник
378
Этот ответ является более правильным, чем то, try itчто текущее поведение не совпадает с гарантированным поведением .
Люк
3
Этот вопрос вступает в игру во время главы Джошуа Блоха о равенстве объектов в Effective Java- amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683
Кевин Мередит
17
В частности, в пункте 8 он отмечает, что в методах equals () один оператор instanceof служит двум целям - он проверяет, что аргумент является ненулевым и имеет правильный тип. "... [S] o вам не нужна отдельная проверка на ноль."
Энди Томас
2
@BenThurley - instanceofоператор Java был частью Java 1.0, выпущенной почти 20 лет назад. Изменение поведения таким образом, что это нарушит существующий код, маловероятно, если не будет некоторой выгоды, которая перевешивает эту огромную стоимость. Двадцать лет назад, возможно, могли быть аргументы для возврата истины, если аргумент мог быть приведен, или для исключения нулевого аргумента. Но эти определения потребовали бы отдельных нулевых проверок.
Энди Томас
3
@BenThurley - поведение гарантируется спецификациями Java прошлого и настоящего. Я думаю, что точка зрения Люка касается ограничений экспериментов при определении гарантированного поведения настоящего.
Энди Томас
267

Использование нулевой ссылки в качестве первого операнда для instanceofвозврата false.

Bozho
источник
268
(И теперь это занимает 10 секунд, чтобы найти этот вопрос в Google)
PL_kolek
73

Очень хороший вопрос. Я просто попробовал для себя.

public class IsInstanceOfTest {

    public static void main(final String[] args) {

        String s;

        s = "";

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));

        s = null;

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));
    }
}

Печать

true
true
false
false

JLS / 15.20.2. Оператор сравнения типов instanceof

Во время выполнения результатом instanceofоператора является то, что trueесли значение RelationalExpression отсутствует, nullи ссылка может быть приведена к ReferenceType без вызова a ClassCastException. В противном случае результат false.

API / Class # isInstance (Объект)

Если этот Classобъект представляет интерфейс, этот метод возвращает, trueесли класс или любой суперкласс указанного Objectаргумента реализует этот интерфейс; это возвращается falseиначе. Если этот Classобъект представляет примитивный тип, этот метод возвращает false.

Джин Квон
источник
Вроде путаницы. s является строкой, потому что она говорит "String s", s не является строкой, потому что это нуль. Так что, черт возьми, с?
Кай Ван
1
@KaiWang s- это просто ссылка на объект. Он может ссылаться на реально существующий объект ( "") или может ссылаться на () nullбуквальную ссылку.
Джин Квон
Я все еще в замешательстве. s может быть нулевым сейчас, но его можно указать только на экземпляр String позже. На него нельзя указывать целое число. Так что это все еще своего рода строка, даже если это ноль. Просто не имеет особого смысла ...
Кай Ван
@KaiWang Вы путаете тип переменной с типом реального объекта. Переменные не являются экземплярами; они фактически просто указатели. nullне строковые данные, независимо от того, какая переменная указывает на них. s instanceof Stringэто не то же самое, что field.getType().equals(String.class), например.
Мэтью Прочитал
@KaiWang, вы должны представить, что в вызове s instanceof Stringпроисходит sзамена на фактическое значение, так что это станет "" instanceof Stringи null instanceof String. Думая об этом, как это может иметь больше смысла.
Тимо Тюршманн
24

Нет, это не так. instanceofвернется , falseесли его первый операнд null.

RoflcoptrException
источник
16

Просто как лакомый кусочек :

Даже вернется .(((A)null)instanceof A)false


(Если приведение типов nullкажется удивительным, иногда вам приходится делать это, например, в таких ситуациях:

public class Test
{
  public static void test(A a)
  {
    System.out.println("a instanceof A: " + (a instanceof A));
  }

  public static void test(B b) {
    // Overloaded version. Would cause reference ambiguity (compile error)
    // if Test.test(null) was called without casting.
    // So you need to call Test.test((A)null) or Test.test((B)null).
  }
}

Так что Test.test((A)null)буду печатать a instanceof A: false.)


PS: Если вы нанимаете, пожалуйста, не используйте это как вопрос собеседования. : D

Аттила Таньи
источник
7

Нет . Java-литерал nullне является экземпляром какого-либо класса. Поэтому он не может быть экземпляром какого-либо класса. instanceof вернет либо falseили,true следовательно, <referenceVariable> instanceof <SomeClass>возвращает, falseкогда referenceVariableзначение равно нулю.

Разработчик Мариус Жиленас
источник
5
Это объяснение звучит странно круглым ... но я знаю, что вы имеете в виду :-)
Крис
@ Крис ты за комментарий Я понял, что ты имеешь в виду :). Отредактировал ответ немного :).
Разработчик Marius Žilėnas
1

instanceofОператор не нуждается в явных nullпроверок, так как он не бросать , NullPointerExceptionесли операнд null.

Во время выполнения результат instanceofоператора равен true, если значение реляционного выражения не равно nullи ссылка может быть приведена к ссылочному типу без вызова исключения преобразования класса.

Если операнд есть null, instanceofоператор возвращается falseи, следовательно, явные проверки на ноль не требуются.

Рассмотрим приведенный ниже пример,

public static void main(String[] args) {
         if(lista != null && lista instanceof ArrayList) {                     //Violation
                System.out.println("In if block");
         }
         else {
                System.out.println("In else block");
         }
}

Правильное использование, instanceofкак показано ниже,

public static void main(String[] args) {
      
         if(lista instanceof ArrayList){                     //Correct way
                  System.out.println("In if block");
         }
            else {
                 System.out.println("In else block");
         }  
}
Нихил Кумар
источник