¿Qué son las excepciones de puntero nulo ( java.lang.NullPointerException) y qué las causa?
¿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?
fuente
¿Qué son las excepciones de puntero nulo ( java.lang.NullPointerException) y qué las causa?
¿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?
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 xes an inty Java la inicializará 0por usted. Cuando le asigna el valor de 10en la segunda línea, su valor de 10se 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 Integerque 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 newpalabra clave se usa para crear instancias (o crear) un objeto de tipo Integery la variable de puntero numse asigna a ese Integerobjeto.
Esto NullPointerExceptionocurre 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 numANTES 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, objes null. Si el método pretende hacer algo al objeto pasado, es apropiado lanzarlo NullPointerExceptionporque 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=bpuede arrojar un NPE si b es unInteger. Hay casos en los que esto es confuso para depurar.NullPointerExceptionproblemas en su código es para uso@Nullabley@NotNullanotaciones. 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?)NullPointerExceptions 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 laNullPointerExceptionpágina de javadoc.Probablemente el código de ejemplo más rápido que se me ocurrió para ilustrar un
NullPointerExceptionsería:En la primera línea adentro
main, estoy configurando explícitamente elObjectreferenciaobjigual 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 unNullPointerExceptionporque 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
nullantes 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
printStringmétodo). Mire la línea y verifique qué valores son nulos agregando declaraciones de registro o utilizando un depurador . Descubrimos queses nulo, y llamar allengthmé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
sse pasa conprintString(name)elprint()método ythis.namees nulo.Rastrear dónde deben establecerse estos valores
¿Dónde se
this.nameestablece? 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
setNamepuede evitar que se establezca como nulo):El método
printoprintStringpuede verificar nulo , por ejemplo:O puede diseñar la clase para que
namesiempre 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,nullque es la forma en que Java dice "sin objeto".A
NullPointerExceptionse lanza en tiempo de ejecución cada vez que su programa intenta usar unnullcomo si fuera una referencia real. Por ejemplo, si escribe esto:la declaración etiquetada "AQUÍ" intentará ejecutar el
length()método en unanullreferencia, y esto arrojará unNullPointerException.Hay muchas formas en que podría usar un
nullvalor que resultará en aNullPointerException. De hecho, las únicas cosas que puede hacernullsin 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
javaccompilador 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.NullPointerExceptiones 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:
mainmétodo de laTestclase.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
footiene el valornull. Luego intentamos ejecutar ellength()métodonully ... ¡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.Stringclase y en la línea 4 deTest.javaserí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:
baresnullentoncesbar[pos]arrojará un NPE.bar[pos]senullentonces 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
barviene Es un parámetro para latestllamada al método, y si observamos cómotestse llamó, podemos ver que proviene de lafoovariable estática. Además, podemos ver claramente que inicializamosfooa un valor no nulo. Eso es suficiente para descartar provisionalmente esta explicación. (En teoría, algo más podría cambiarfooanull... pero eso no está sucediendo aquí).Entonces, ¿qué pasa con nuestro segundo escenario? Bueno, podemos ver que
poses1, 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
NullPointerExceptionque 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:
nullobjeto.nullobjeto.nullcomo si fuera una matriz.nullcomo si fuera una matriz.nullcomo si fuera un valor Lanzable.Las aplicaciones deben lanzar instancias de esta clase para indicar otros usos ilegales de
nullobjeto.Referencia: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
fuente
nullcomo objetivo de unsynchronizedbloque, 2) usando anullcomo objetivo de aswitchy unboxingnull.Un
nullpuntero es aquel que apunta a ninguna parte. Cuando desreferencia un punterop, dices "dame los datos en la ubicación almacenada en" p ". Cuandopes unnullpuntero, la ubicación almacenadapesnowhere, 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
NULLestá escrito comonullen 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
NullPointerExceptions.Ver también: una buena lista de mejores prácticas
Yo agregaría, muy importante, hacer un buen uso del
finalmodificador. Usar el modificador "final" siempre que sea aplicable en JavaResumen:
finalmodificador para hacer cumplir una buena inicialización.@NotNully@Nullableif("knownObject".equals(unknownObject)valueOf()sobretoString().StringUtilsmétodos seguros nulosStringUtils.isEmpty(null).fuente
@Nullablecomo 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
NullPointerExceptionsurja.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
thisreferencias. 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
referenceyotherReferencetanto 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
NullPointerExceptionocurre 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
.equalsen 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
Optionalera volver nulo. La palabra clave está bien. Saber cómo protegerse es fundamental. Esto ofrece una ocurrencia común y formas de mitigarlo.