java - ¿Por qué int num=Integer.getInteger("123") lanza NullPointerException?
api-design autoboxing (3)
El siguiente código arroja NullPointerException
:
int num = Integer.getInteger("123");
¿Mi compilador invoca a getInteger
en nulo porque es estático? ¡Eso no tiene ningún sentido!
¿Qué esta pasando?
El panorama
Hay dos cuestiones en juego aquí:
-
Integer getInteger(String)
no hace lo que crees que hace- Devuelve
null
en este caso
- Devuelve
- la asignación de
Integer
aint
causa auto-unboxing- Dado que el
Integer
esnull
, se lanzaNullPointerException
- Dado que el
Para analizar (String) "123"
a (int) 123
, puede usar, por ejemplo, int Integer.parseInt(String)
.
Referencias
Referencias de la API Integer
En Integer.getInteger
Esto es lo que la documentación tiene que decir sobre lo que hace este método:
public static Integer getInteger(String nm)
: Determina el valor entero de la propiedad del sistema con el nombre especificado. Si no hay una propiedad con el nombre especificado, si el nombre especificado es vacío onull
, o si la propiedad no tiene el formato numérico correcto, se devuelvenull
.
En otras palabras, este método no tiene nada que ver con analizar un String
a un valor int/Integer
, sino que tiene que ver con el método System.getProperty
.
Es cierto que esto puede ser una gran sorpresa. Es desafortunado que la biblioteca tenga sorpresas como esta, pero te enseña una valiosa lección: siempre busca la documentación para confirmar lo que hace un método.
De forma coincidente, una variación de este problema se presentó en Return of the Puzzlers: Schlock and Awe (TS-5186) , Josh Bloch y Neal Gafter en la presentación de la sesión técnica de JavaOne 2009. Aquí está la diapositiva final:
La moral
- Métodos extraños y terribles acechan en las bibliotecas
- Algunos tienen nombres que suenan inocuos
- Si tu código se comporta mal
- Asegúrate de estar llamando a los métodos correctos
- Lea la documentación de la biblioteca
- Para diseñadores de API
- No viole el principio de menos asombro
- No viole la jerarquía de abstracción
- No use nombres similares para comportamientos muy diferentes
Para completar, también existen estos métodos que son análogos a Integer.getInteger
:
Preguntas relacionadas
- La violación más asombrosa del principio de asombro mínimo
- ¿El método más torpe / engañoso en Java Base API?
En autounboxing
El otro problema, por supuesto, es cómo se lanza la NullPointerException
. Para enfocarnos en este tema, podemos simplificar el fragmento de la siguiente manera:
Integer someInteger = null;
int num = someInteger; // throws NullPointerException!!!
Aquí hay una cita de Effective Java 2nd Edition, Item 49: Prefiere los tipos primitivos a las primitivas en recuadro:
En resumen, use primitivas en lugar de primitivas en caja siempre que tenga la opción. Los tipos primitivos son más simples y rápidos. Si debe usar primitivos en caja, ¡tenga cuidado! El Autoboxing reduce la verbosidad, pero no el peligro, del uso de primitivas en caja. Cuando su programa compara dos primitivas encuadradas con el operador
==
, realiza una comparación de identidad, que seguramente no es lo que usted desea. Cuando su programa realiza cálculos mixtos que involucran primitivas en caja y sin caja, lo hace unboxing, y cuando su programa realiza unboxing, puede lanzarNullPointerException
. Finalmente, cuando su programa contiene valores primitivos, puede generar creaciones de objetos costosas e innecesarias.
Hay lugares en los que no tiene más remedio que utilizar primitivas en recuadro, por ejemplo, genéricos, pero, en caso contrario, debería considerar seriamente si la decisión de utilizar primitivas en recuadro está justificada.
Preguntas relacionadas
- ¿Cuál es la diferencia entre un int y un entero en Java / C #?
- ¿Por qué el autoboxing en Java me permite tener 3 valores posibles para un booleano?
- ¿Se garantiza que el nuevo entero (i) == i en Java? (¡¡¡SÍ!!!)
- Cuando se comparan dos enteros en Java, ¿se produce un desempaquetado automático? (¡¡¡NO!!!)
- Java noob: genéricos sobre objetos solamente? (sí, desafortunadamente)
Consulte la documentación del método getInteger() . En este método, el parámetro String
es una propiedad del sistema que determina el valor entero de la propiedad del sistema con el nombre especificado. "123" no es el nombre de ninguna propiedad del sistema, como se explica here . Si desea convertir esta cadena a int
, entonces use el método como int num = Integer.parseInt("123")
.
Desde http://konigsberg.blogspot.com/2008/04/integergetinteger-are-you-kidding-me.html :
getInteger ''Determina el valor entero de la propiedad del sistema con el nombre especificado.''
Tu quieres esto:
Integer.parseInt("123")