Tengo este codigo:
package tests;
import java.util.Hashtable;
public class Tests {
public static void main(String[] args) {
Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();
System.out.println("TEST 1");
System.out.println(modifiedItems.get("item1")); // Prints null
System.out.println("TEST 2");
System.out.println(modifiedItems.get("item1") == null); // Prints true
System.out.println("TEST 3");
System.out.println(Boolean.valueOf(null)); // Prints false
System.out.println("TEST 4");
System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
System.out.println("FINISHED!"); // Never executed
}
}
Mi problema es que no entiendo por qué la Prueba 3 funciona bien (imprime false
y no produce NullPointerException
) mientras que la Prueba 4 arroja un NullPointerException
. Como puede ver en las pruebas 1 y 2 , null
y modifiedItems.get("item1")
son iguales y null
.
El comportamiento es el mismo en Java 7 y 8.
java
nullpointerexception
boolean
David E
fuente
fuente
null
a la misma función no genera un NPE! Hay una buena razón para ello, pero ciertamente es confuso a primera vista :-)==
se aplica.Respuestas:
Debe observar cuidadosamente qué sobrecarga se está invocando:
Boolean.valueOf(null)
está invocandoBoolean.valueOf(String)
. Esto no arroja unNPE
incluso si se proporciona un parámetro nulo.Boolean.valueOf(modifiedItems.get("item1"))
está invocandoBoolean.valueOf(boolean)
, porquemodifiedItems
los valores de 'son de tipoBoolean
, lo que requiere una conversión de unboxing. Dado quemodifiedItems.get("item1")
esnull
, es el desembalaje de ese valor, no elBoolean.valueOf(...)
, lo que arroja el NPE.Las reglas para determinar qué sobrecarga se invoca son bastante complicadas , pero más o menos son así:
En una primera pasada, se busca una coincidencia de método sin permitir el boxeo / unboxing (ni los métodos de aridad variable).
null
es un valor aceptable para aString
pero noboolean
,Boolean.valueOf(null)
se corresponde conBoolean.valueOf(String)
en esta pasada;Boolean
no es aceptable para ninguno de los dosBoolean.valueOf(String)
oBoolean.valueOf(boolean)
, por lo que ningún método coincide en este pase paraBoolean.valueOf(modifiedItems.get("item1"))
.En una segunda pasada, se busca una coincidencia de método, lo que permite boxear / unboxing (pero aún no métodos de aridad variable).
Boolean
se puede desempaquetarboolean
, por lo queBoolean.valueOf(boolean)
se emparejaBoolean.valueOf(modifiedItems.get("item1"))
en este pase; pero el compilador debe insertar una conversión de unboxing para invocarla:Boolean.valueOf(modifiedItems.get("item1").booleanValue())
(Hay un tercer pase que permite métodos de aridad variable, pero eso no es relevante aquí, ya que los dos primeros pases coincidieron con estos casos)
fuente
Boolean.valueOf(modifiedItems.get("item1").booleanValue())
en el código fuente en lugar deBoolean.valueOf(modifiedItems.get("item1"))
?.booleanValue()
enterrado en la expresión. Dos observaciones: 1) el (des) boxing automático es una característica deliberada de Java para eliminar el cruft sintáctico; hacerlo usted mismo es posible, pero no idiomático; 2) esto no le ayuda en absoluto - ciertamente no evita que ocurra el problema, ni proporciona ninguna información adicional cuando ocurre la falla (el seguimiento de la pila sería idéntico, porque el código ejecutado es idéntico).Dado que
modifiedItems.get
devuelve aBoolean
(que no se puede convertir en aString
), la firma que se usaría esBoolean.valueOf(boolean)
, dondeBoolean
se envía a una primitivaboolean
. Una vez quenull
se devuelve allí, la bandeja de salida falla con unNullPointerException
.fuente
Firma del método
El método
Boolean.valueOf(...)
tiene dos firmas:public static Boolean valueOf(boolean b)
public static Boolean valueOf(String s)
Tu
modifiedItems
valor esBoolean
. No se puede enviarBoolean
a,String
por lo que se elegirá la primera firma.Unboxing booleano
En tu declaración
que se puede leer como
Sin embargo,
modifiedItems.get("item1")
devuelve ,null
por lo que básicamente tendrásque obviamente conduce a un
NullPointerException
fuente
Como Andy ya describió muy bien el motivo de
NullPointerException
:que se debe al desempaquetado booleano:
convertirse en:
en tiempo de ejecución y luego arroja
NullPointerException
simodifiedItems.get("item1")
es nulo.Ahora me gustaría agregar un punto más aquí que el desempaquetado de las siguientes clases a sus respectivas primitivas también puede producir una
NullPointerException
excepción si sus correspondientes objetos devueltos son nulos.Aquí está el código:
fuente
Una forma de entenderlo es cuando
Boolean.valueOf(null)
se invoca, a java se le dice precisamente que evalúe null.Sin embargo, cuando
Boolean.valueOf(modifiedItems.get("item1"))
se invoca, se le dice a java que obtenga un valor de HashTable de tipo de objeto booleano, pero no encuentra el tipo booleano sino que encuentra un callejón sin salida (nulo) a pesar de que esperaba booleano. Se lanza la excepción NullPointerException porque los creadores de esta parte de java decidieron que esta situación es una instancia de algo en el programa que va mal y necesita la atención del programador. (Ocurrió algo no intencionado).En este caso, es más la diferencia entre declarar deliberadamente que pretendía que el nulo estuviera allí y java encontrar una referencia faltante a un objeto (nulo) donde se pretendía encontrar un objeto.
Consulte más información sobre NullPointerException en esta respuesta: https://stackoverflow.com/a/25721181/4425643
fuente