Cuando declara una variable de referencia (es decir, un objeto), realmente está creando un puntero a un objeto. Considere el siguiente código donde declara una variable de tipo primitivo int
:
int x;
x = 10;
En este ejemplo, la variable x
es an int
y Java la inicializará 0
por usted. Cuando le asigna el valor de 10
en la segunda línea, su valor de 10
se escribe en la ubicación de memoria mencionada por x
.
Pero, cuando intenta declarar un tipo de referencia , sucede algo diferente. Toma el siguiente código:
Integer num;
num = new Integer(10);
La primera línea declara una variable llamada num
, pero aún no contiene un valor primitivo. En cambio, contiene un puntero (porque el tipo es el Integer
que es un tipo de referencia). Como todavía no ha dicho a qué apuntar, Java lo establece null
, lo que significa " no estoy apuntando a nada ".
En la segunda línea, la new
palabra clave se usa para crear instancias (o crear) un objeto de tipo Integer
y la variable de puntero num
se asigna a ese Integer
objeto.
Esto NullPointerException
ocurre cuando declaras una variable pero no creas un objeto y la asignas a la variable antes de intentar usar el contenido de la variable (llamada desreferenciación ). Entonces estás señalando algo que en realidad no existe.
La desreferencia generalmente ocurre cuando se usa .
para acceder a un método o campo, o cuando se usa [
para indexar una matriz.
Si intenta desreferenciar num
ANTES de crear el objeto, obtendrá un NullPointerException
. En los casos más triviales, el compilador detectará el problema y le hará saber que " num may not have been initialized
," pero a veces puede escribir código que no crea directamente el objeto.
Por ejemplo, puede tener un método de la siguiente manera:
public void doSomething(SomeObject obj) {
//do something to obj
}
En cuyo caso, no está creando el objeto obj
, sino asumiendo que fue creado antes de doSomething()
que se llamara al método. Tenga en cuenta que es posible llamar al método de esta manera:
doSomething(null);
En cuyo caso, obj
es null
. Si el método pretende hacer algo al objeto pasado, es apropiado lanzarlo NullPointerException
porque es un error del programador y el programador necesitará esa información para fines de depuración. Incluya el nombre de la variable del objeto en el mensaje de excepción, como
Objects.requireNonNull(a, "a");
Alternativamente, puede haber casos en los que el propósito del método no sea únicamente operar sobre el objeto pasado y, por lo tanto, un parámetro nulo puede ser aceptable. En este caso, necesitaría verificar un parámetro nulo y comportarse de manera diferente. También debe explicar esto en la documentación. Por ejemplo, doSomething()
podría escribirse como:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
Finalmente, cómo identificar la excepción y la causa usando Stack Trace
¿Qué métodos / herramientas se pueden usar para determinar la causa de modo que evite que la excepción haga que el programa finalice prematuramente?
La sonda con findbugs puede detectar NPE.
¿Puede la sonda detectar excepciones de puntero nulo causadas por JVM dinámicamente?
int a=b
puede arrojar un NPE si b es unInteger
. Hay casos en los que esto es confuso para depurar.NullPointerException
problemas en su código es para uso@Nullable
y@NotNull
anotaciones. La siguiente respuesta tiene más información sobre esto. Aunque esta respuesta se refiere específicamente al IDE de IntelliJ, también es aplicable a otras herramientas, como se muestra en los comentarios. (Por cierto, no se me permite editar esta respuesta directamente, ¿tal vez el autor puede agregarla?)NullPointerException
s son excepciones que ocurren cuando intenta utilizar una referencia que apunta a ninguna ubicación en la memoria (nulo) como si estuviera haciendo referencia a un objeto. Llamar a un método en una referencia nula o intentar acceder a un campo de una referencia nula activará aNullPointerException
. Estos son los más comunes, pero se enumeran otras formas en laNullPointerException
página de javadoc.Probablemente el código de ejemplo más rápido que se me ocurrió para ilustrar un
NullPointerException
sería:En la primera línea adentro
main
, estoy configurando explícitamente elObject
referenciaobj
igual anull
. Esto significa que tengo una referencia, pero no apunta a ningún objeto. Después de eso, trato de tratar la referencia como si apuntara a un objeto llamando a un método. Esto da como resultado unNullPointerException
porque no hay código para ejecutar en la ubicación a la que apunta la referencia.(Esto es un tecnicismo, pero creo que vale la pena mencionar: una referencia que apunta a nulo no es lo mismo que un puntero C que apunta a una ubicación de memoria no válida. Un puntero nulo literalmente no apunta a ninguna parte , que es sutilmente diferente de apuntando a una ubicación que resulta no válida).
fuente
null
antes de usarla, como este . Con las variables locales, el compilador detectaría este error, pero en este caso no lo hace. ¿Tal vez eso sería una adición útil a su respuesta?¿Qué es una excepción NullPointerException?
Un buen lugar para comenzar es los JavaDocs . Tienen esto cubierto:
También es el caso de que si intenta utilizar una referencia nula con
synchronized
, eso también arrojará esta excepción, según el JLS :¿Cómo lo soluciono?
Entonces tienes un
NullPointerException
. Como lo arreglas? Tomemos un ejemplo simple que arroja unNullPointerException
:Identificar los valores nulos.
El primer paso es identificar exactamente qué valores están causando la excepción . Para esto, necesitamos hacer alguna depuración. Es importante aprender a leer un stacktrace . Esto le mostrará dónde se produjo la excepción:
Aquí, vemos que la excepción se lanza en la línea 13 (en el
printString
método). Mire la línea y verifique qué valores son nulos agregando declaraciones de registro o utilizando un depurador . Descubrimos ques
es nulo, y llamar allength
método en él arroja la excepción. Podemos ver que el programa deja de lanzar la excepción cuandos.length()
se elimina del método.Rastree de dónde provienen estos valores
Luego verifique de dónde proviene este valor. Al seguir los llamadores del método, vemos que
s
se pasa conprintString(name)
elprint()
método ythis.name
es nulo.Rastrear dónde deben establecerse estos valores
¿Dónde se
this.name
establece? En elsetName(String)
metodo. Con un poco más de depuración, podemos ver que este método no se llama en absoluto. Si se llamó al método, asegúrese de verificar el orden en que se llama a estos métodos, y el método establecido no se llama después del método print.Esto es suficiente para darnos una solución: agregue una llamada
printer.setName()
antes de llamarprinter.print()
.Otras correcciones
La variable puede tener un valor predeterminado (y
setName
puede evitar que se establezca como nulo):El método
print
oprintString
puede verificar nulo , por ejemplo:O puede diseñar la clase para que
name
siempre tenga un valor no nulo :Ver también:
Todavía no puedo encontrar el problema.
Si trató de depurar el problema y aún no tiene una solución, puede publicar una pregunta para obtener más ayuda, pero asegúrese de incluir lo que ha intentado hasta ahora. Como mínimo, incluya el stacktrace en la pregunta y marque los números de línea importantes en el código. Además, intente simplificar el código primero (vea SSCCE ).
fuente
Pregunta: ¿Qué causa un
NullPointerException
(NPE)?Como usted debe saber, tipos de Java se dividen en tipos primitivos (
boolean
,int
, etc.) y los tipos de referencia . Los tipos de referencia en Java le permiten utilizar el valor especial,null
que es la forma en que Java dice "sin objeto".A
NullPointerException
se lanza en tiempo de ejecución cada vez que su programa intenta usar unnull
como si fuera una referencia real. Por ejemplo, si escribe esto:la declaración etiquetada "AQUÍ" intentará ejecutar el
length()
método en unanull
referencia, y esto arrojará unNullPointerException
.Hay muchas formas en que podría usar un
null
valor que resultará en aNullPointerException
. De hecho, las únicas cosas que puede hacernull
sin causar un NPE son:==
u!=
operadores, oinstanceof
.Pregunta: ¿Cómo leo el stacktrace de NPE?
Supongamos que compilo y ejecuto el programa anterior:
Primera observación: ¡la compilación tiene éxito! El problema en el programa NO es un error de compilación. Es un error de tiempo de ejecución . (Algunos IDEs pueden advertir que su programa siempre arrojará una excepción ... pero el estándar
javac
compilador no lo hace).Segunda observación: cuando ejecuto el programa, genera dos líneas de "gobbledy-gook". ¡¡INCORRECTO!! Eso no es gobbledy-gook. Es un stacktrace ... y proporciona información vital. que lo ayudará a rastrear el error en su código si se toma el tiempo de leerlo cuidadosamente.
Así que echemos un vistazo a lo que dice:
La primera línea del seguimiento de la pila te dice varias cosas:
java.lang.NullPointerException
.NullPointerException
es inusual a este respecto, porque rara vez tiene un mensaje de error.La segunda línea es la más importante para diagnosticar un NPE.
Esto nos dice una serie de cosas:
main
método de laTest
clase.Si cuenta las líneas en el archivo anterior, la línea 4 es la que etiqueté con el comentario "AQUÍ".
Tenga en cuenta que, en un ejemplo más complicado, habrá muchas líneas en el seguimiento de la pila NPE. Pero puede estar seguro de que la segunda línea (la primera línea "en") le dirá dónde se arrojó el NPE 1 .
En resumen, el seguimiento de la pila nos dirá inequívocamente qué afirmación del programa ha arrojado el NPE.
1 - No del todo cierto. Hay cosas llamadas excepciones anidadas ...
Pregunta: ¿Cómo puedo localizar la causa de la excepción NPE en mi código?
Esta es la parte difícil. La respuesta corta es aplicar inferencia lógica a la evidencia proporcionada por el seguimiento de la pila, el código fuente y la documentación API relevante.
Vamos a ilustrar primero con el ejemplo simple (arriba). Comenzamos mirando la línea que el seguimiento de la pila nos ha dicho es donde ocurrió el NPE:
¿Cómo puede eso arrojar un NPE?
De hecho, solo hay una forma: solo puede suceder si
foo
tiene el valornull
. Luego intentamos ejecutar ellength()
métodonull
y ... ¡BANG!Pero (te escucho decir) qué pasa si el NPE se arrojó dentro del
length()
llamada método?Bueno, si eso sucediera, el seguimiento de la pila se vería diferente. La primera línea "en" diría que la excepción se lanzó en alguna línea de la
java.lang.String
clase y en la línea 4 deTest.java
sería la segunda línea "en".Entonces, ¿de dónde vino eso
null
? En este caso, es obvio, y es obvio lo que debemos hacer para solucionarlo. (Asigne un valor no nulo afoo
).Bien, intentemos con un ejemplo un poco más complicado. Esto requerirá alguna deducción lógica .
Así que ahora tenemos dos líneas "en". El primero es para esta línea:
y el segundo es para esta línea:
Mirando la primera línea, ¿cómo podría eso arrojar un NPE? Hay dos maneras:
bar
esnull
entoncesbar[pos]
arrojará un NPE.bar[pos]
senull
entonces llamalength()
en él arrojará una NPE.A continuación, tenemos que averiguar cuál de esos escenarios explica lo que realmente está sucediendo. Comenzaremos explorando el primero:
De donde
bar
viene Es un parámetro para latest
llamada al método, y si observamos cómotest
se llamó, podemos ver que proviene de lafoo
variable estática. Además, podemos ver claramente que inicializamosfoo
a un valor no nulo. Eso es suficiente para descartar provisionalmente esta explicación. (En teoría, algo más podría cambiarfoo
anull
... pero eso no está sucediendo aquí).Entonces, ¿qué pasa con nuestro segundo escenario? Bueno, podemos ver que
pos
es1
, lo que significa quefoo[1]
debe sernull
. es posible?¡De hecho, es! Y ese es el problema. Cuando inicializamos así:
asignamos a
String[]
con dos elementos que se inicializannull
. Después de eso, no hemos cambiado el contenido defoo
... asífoo[1]
seránull
.fuente
Es como si estuviera intentando acceder a un objeto que es
null
. Considere el siguiente ejemplo:En este momento, acaba de declarar este objeto pero no se ha inicializado o instanciado . Y cada vez que intente acceder a cualquier propiedad o método, arrojará lo
NullPointerException
que tenga sentido.Vea este ejemplo a continuación también:
fuente
Se produce una excepción de puntero nulo cuando una aplicación intenta usar nulo en un caso donde se requiere un objeto. Éstos incluyen:
null
objeto.null
objeto.null
como si fuera una matriz.null
como si fuera una matriz.null
como si fuera un valor Lanzable.Las aplicaciones deben lanzar instancias de esta clase para indicar otros usos ilegales de
null
objeto.Referencia: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
fuente
null
como objetivo de unsynchronized
bloque, 2) usando anull
como objetivo de aswitch
y unboxingnull
.Un
null
puntero es aquel que apunta a ninguna parte. Cuando desreferencia un punterop
, dices "dame los datos en la ubicación almacenada en" p ". Cuandop
es unnull
puntero, la ubicación almacenadap
esnowhere
, estás diciendo" dame los datos en la ubicación 'en ninguna parte' ". Obviamente, no puede hacer esto, por lo que arroja unnull pointer exception
.En general, es porque algo no se ha inicializado correctamente.
fuente
NULL
está escrito comonull
en java. Y es algo sensible a mayúsculas y minúsculas.Ya hay muchas explicaciones para explicar cómo sucede y cómo solucionarlo, pero también debe seguir las mejores prácticas para evitar
NullPointerException
s.Ver también: una buena lista de mejores prácticas
Yo agregaría, muy importante, hacer un buen uso del
final
modificador. Usar el modificador "final" siempre que sea aplicable en JavaResumen:
final
modificador para hacer cumplir una buena inicialización.@NotNull
y@Nullable
if("knownObject".equals(unknownObject)
valueOf()
sobretoString()
.StringUtils
métodos seguros nulosStringUtils.isEmpty(null)
.fuente
@Nullable
como se enumeran anteriormente) y advierten sobre posibles errores. También es posible inferir y generar tales anotaciones (por ejemplo, IntelliJ puede hacer eso) basándose en la estructura de código existente.if (obj==null)
. Si es nulo, entonces debe escribir código para manejar eso también.En Java, todo (excepto los tipos primitivos) tiene la forma de una clase.
Si desea utilizar cualquier objeto, entonces tiene dos fases:
Ejemplo:
Object object;
object = new Object();
Lo mismo para el concepto de matriz:
Item item[] = new Item[5];
item[0] = new Item();
Si no está dando la sección de inicialización, entonces
NullPointerException
surja.fuente
Una excepción de puntero nulo es un indicador de que está utilizando un objeto sin inicializarlo.
Por ejemplo, a continuación hay una clase de estudiante que la usará en nuestro código.
El siguiente código le ofrece una excepción de puntero nulo.
Porque está utilizando
student
, pero olvidó inicializarlo como en el código correcto que se muestra a continuación:fuente
En java todas las variables que declaras son en realidad "referencias" a los objetos (o primitivas) y no a los objetos en sí.
Cuando intenta ejecutar un método de objeto, la referencia le pide al objeto vivo que ejecute ese método. Pero si la referencia hace referencia a NULL (nada, cero, vacío, nada), entonces no hay forma de que el método se ejecute. Luego, el tiempo de ejecución le permite saber esto lanzando una NullPointerException.
Su referencia está "apuntando" a nulo, por lo tanto, "Nulo -> Puntero".
El objeto vive en el espacio de memoria de VM y la única forma de acceder a él es utilizando
this
referencias. Toma este ejemplo:Y en otro lugar en tu código:
Esta una cosa importante a saber - cuando no hay más referencias a un objeto (en el ejemplo anterior cuando
reference
yotherReference
tanto punto a null) entonces el objeto es "inalcanzable". No hay forma de que podamos trabajar con él, por lo que este objeto está listo para ser recolectado, y en algún momento, la máquina virtual liberará la memoria utilizada por este objeto y asignará otro.fuente
Otra ocurrencia de a
NullPointerException
ocurre cuando uno declara una matriz de objetos, e inmediatamente trata de desreferenciar elementos dentro de ella.Este NPE particular puede evitarse si se invierte el orden de comparación; a saber, uso
.equals
en un objeto no nulo garantizado.Todos los elementos dentro de una matriz se inicializan a su valor inicial común ; para cualquier tipo de matriz de objetos, eso significa que todos los elementos son
null
.Usted debe inicializar los elementos de la matriz antes de acceder o eliminación de referencias a ellos.
fuente
Optional
era volver nulo. La palabra clave está bien. Saber cómo protegerse es fundamental. Esto ofrece una ocurrencia común y formas de mitigarlo.