¿Por qué puedo arrojar nulo en Java? [duplicar]
Al ejecutar esto:
public class WhatTheShoot {
public static void main(String args[]){
try {
throw null;
} catch (Exception e){
System.out.println(e instanceof NullPointerException);
System.out.println(e instanceof FileNotFoundException);
}
}
}
La respuesta es:
true
false
Lo cual fue bastante sorprendente para mí. Pensé que esto generaría un error en tiempo de compilación.
¿Por qué puedo arrojar un valor nulo en Java y por qué lo convierte en una excepción NullPointerException?
(En realidad, no sé si es un "upcast", dado que estoy arrojando nulo)
Aparte de una pregunta de entrevista realmente estúpida (por favor, que nadie haga esto en una entrevista), no veo ninguna razón para hacerlo throw null
. Tal vez quieras que te despidan, pero eso es... Quiero decir, ¿por qué si no querría alguien throw null
?
Dato curioso: IntelliJ IDEA 12 me dice que mi línea e instanceof NullPointerException
siempre será falsa. Lo cual no es del todo cierto.
Parece que no es que null
se trate como un NullPointerException
, sino que el acto de intentarlo throw null
arroja un NullPointerException
.
En otras palabras, throw
comprueba que su argumento no sea nulo y, si es nulo, arroja un archivo NullPointerException
.
JLS 14.18 especifica este comportamiento:
Si la evaluación de la expresión se completa normalmente y produce un valor nulo, entonces se crea y se lanza una instancia V' de la clase NullPointerException en lugar de nula. La declaración de lanzamiento luego se completa abruptamente, siendo el motivo un lanzamiento con valor V'.
¿Por qué lo convierte en NullPointerException?
Según JLS 14.18 :
Una declaración de lanzamiento primero evalúa la expresión. Si la evaluación de la Expresión se completa abruptamente por algún motivo, entonces el lanzamiento se completa abruptamente por ese motivo. Si la evaluación de la Expresión se completa normalmente, produciendo un valor V no nulo, entonces la declaración de lanzamiento se completa abruptamente, la razón es un lanzamiento con valor V. Si la evaluación de la Expresión se completa normalmente, produciendo un valor nulo, entonces se crea una instancia V' de la clase NullPointerException se crea y se lanza en lugar de nulo. La declaración de lanzamiento luego se completa abruptamente, siendo el motivo un lanzamiento con valor V'.
¿Por qué puedo arrojar nulo en Java?
Puedes lanzar objetos de tipo Throwable
y como null
es una referencia válida para Throwable
, el compilador lo permite.
Esto es lo que dice Neal Gafter ( archivado )
Aunque nulo se puede asignar a cada tipo de referencia, el tipo nulo no es en sí mismo un tipo de referencia. Nuestra intención era eliminar el requisito de que la expresión en una declaración de lanzamiento fuera un tipo de referencia de la tercera edición de JLS, pero ese cambio nunca llegó a la versión publicada. Por lo tanto, este es un error del compilador javac que introduje en SE 5.
Se comporta de conformidad con el JLS :
Si la evaluación de la expresión se completa normalmente y produce un valor nulo, entonces se crea y se lanza una instancia V' de la clase NullPointerException en lugar de nula.
Pensarlo de esta manera hace que sea un poco más obvio por qué funciona esto:
try {
Exception foo = null;
if(false) {
foo = new FileNotFoundException();
} // Oops, forgot to set foo for the true case..
throw foo;
} catch (Exception e){
System.out.println(e instanceof NullPointerException);
System.out.println(e instanceof FileNotFoundException);
}