¿Es necesario un control nulo antes de llamar a instanceof?

1354

Será null instanceof SomeClassvolver falseo lanzar una NullPointerException?

Johan Lübcke
fuente
También es 'importante' o al menos muy útil como línea de inicio (o muy temprana) de 'mejor práctica' para cualquier método de comparación o igual o similar que esté diseñado para tener éxito solo en objetos no nulos del mismo tipo, y te protege contra los 'casos tontos' en una sola línea. menos código = menos errores.
13
Para evaluar el "¿es útil?" debate: nunca he escrito mi propio código Java (por lo que no sé fácilmente dónde están las especificaciones, y compilar una prueba no sería muy trivial), pero actualmente estoy convirtiendo manualmente Java a JavaScript. Mi código estaba fallando en una referencia nula, y buscar en Google me permitió ver la respuesta aceptada, que confirmó que era un comportamiento esperado y que me faltaba una verificación nula implícita. Muy útil, en mi caso.
Scott Mermelstein

Respuestas:

1839

No, no es necesaria una verificación nula antes de usar instanceof.

La expresión x instanceof SomeClasses falsesi xes null.

De la Especificación del lenguaje Java, sección 15.20.2, "Operador de comparación de tipos instanceof" :

"En el tiempo de ejecución, el resultado del instanceofoperador es truesi el valor de RelationalExpression no esnull y la referencia podría convertirse al ReferenceType sin generar un ClassCastException. De lo contrario, el resultado es false".

Entonces, si el operando es nulo, el resultado es falso.

Andy Thomas
fuente
377
Esta respuesta es más correcta que try itporque el comportamiento actual no es lo mismo que el comportamiento garantizado .
Lucas
3
Esta pregunta entra en juego durante el capítulo de Joshua Bloch en igualdad de objetos en Effective Java- amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683
Kevin Meredith
17
Específicamente, en el ítem 8, señala que en los métodos equals (), una instancia de operador tiene dos propósitos: verifica que el argumento sea no nulo y del tipo correcto. "... [S] o no necesita un cheque nulo por separado".
Andy Thomas el
2
@BenThurley: el instanceofoperador de Java era parte de Java 1.0, lanzado hace casi 20 años. Cambiar el comportamiento ahora de una manera que rompería el código existente es poco probable, a falta de algún beneficio que supere ese enorme costo. Hace veinte años, tal vez podría haber argumentos para devolver verdadero si el argumento pudiera ser lanzado, o lanzar una excepción para un argumento nulo. Pero esas definiciones habrían requerido verificaciones nulas separadas.
Andy Thomas
3
@BenThurley: el comportamiento está garantizado por las especificaciones de Java pasadas y presentes. Creo que el punto de Luke aborda las limitaciones de la experimentación para determinar el comportamiento garantizado del presente.
Andy Thomas
267

Usando una referencia nula como el primer operando para instanceofretornos false.

Bozho
fuente
268
(Y ahora toma 10 segundos encontrar esta pregunta en Google)
PL_kolek
73

Muy buena pregunta de hecho. Solo lo intenté por mí mismo.

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));
    }
}

Huellas dactilares

true
true
false
false

JLS / 15.20.2. Operador de comparación de tipos instanceof

En tiempo de ejecución, el resultado del instanceofoperador es truesi el valor de RelationalExpression no es nully la referencia podría convertirse al ReferenceType sin generar a ClassCastException. De lo contrario, el resultado es false.

API / Class # isInstance (Object)

Si este Classobjeto representa una interfaz, este método devuelve truesi la clase o cualquier superclase del Objectargumento especificado implementa esta interfaz; vuelve de falseotra manera. Si este Classobjeto representa un tipo primitivo, este método devuelve false.

Jin Kwon
fuente
Un poco confuso. s es una cadena porque dice "cadena s", s no es una cadena porque es nula. Entonces, ¿qué demonios es s?
Kai Wang
1
@KaiWang ses solo una variable de referencia de objeto. Puede hacer referencia a un objeto realmente existente ( "") o puede hacer referencia a (la) nullreferencia literal.
Jin Kwon
Todavía estoy confundido. s podría ser nulo ahora, pero solo puede apuntar a una instancia de String más adelante. No se puede señalar, como, un número entero. Por lo tanto, sigue siendo una especie de cadena, incluso es nula. Simplemente no tiene mucho sentido ...
Kai Wang
@KaiWang Está confundiendo el tipo de variable con el tipo del objeto real. Las variables no son instancias; son efectivamente solo punteros. nullno son datos de cadena, no importa qué variable lo apunte. s instanceof Stringno es lo mismo que field.getType().equals(String.class), por ejemplo.
Mateo leyó el
@KaiWang hay que imaginar que en la llamada de s instanceof Stringla ses reemplazado con el valor real, por lo que se convertiría en "" instanceof Stringy null instanceof String. Pensar así puede tener más sentido.
Timo Türschmann 01 de
24

No, no es. instanceofvolvería falsesi su primer operando es null.

RoflcoptrException
fuente
16

Solo como un bocado :

Incluso volveremos .(((A)null)instanceof A)false


(Si la conversión tipográfica nullparece sorprendente, a veces hay que hacerlo, por ejemplo en situaciones como esta:

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).
  }
}

Entonces Test.test((A)null)imprimirá a instanceof A: false.)


PD: Si está contratando, no use esto como una pregunta de entrevista de trabajo. :RE

Atila Tanyi
fuente
7

No se . El literal de Java nullno es una instancia de ninguna clase. Por lo tanto, no puede ser una instancia de ninguna clase. instanceof devolverá uno falseo,true por lo tanto, los <referenceVariable> instanceof <SomeClass>retornos falsecuando el referenceVariablevalor sea nulo.

Desarrollador Marius Žilėnas
fuente
55
Esa explicación suena extrañamente circular ... pero sé lo que quieres decir :-)
Kris
@Kris ty por el comentario, entendí lo que quieres decir :). Editó una respuesta un poco :).
Desarrollador Marius Žilėnas
1

El instanceofoperador no necesita nullcomprobaciones explícitas , ya que no arroja un NullPointerExceptionsi el operando es null.

En tiempo de ejecución, el resultado del instanceofoperador es verdadero si el valor de la expresión relacional no lo es nully la referencia podría convertirse al tipo de referencia sin generar una excepción de conversión de clase.

Si el operando es null, el instanceofoperador regresa falsey, por lo tanto, no se requieren comprobaciones nulas explícitas.

Considere el siguiente ejemplo,

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");
         }
}

El uso correcto de instanceofes como se muestra a continuación,

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");
         }  
}
Nikhil Kumar
fuente