¿Qué es una excepción NullPointerException y cómo la soluciono?


210

¿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?

Respuestas:


3767

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?


558
"La mejor manera de evitar este tipo de excepción es verificar siempre que sea nulo cuando no creó el objeto usted mismo". Si la persona que llama pasa nulo, pero nulo no es un argumento válido para el método, entonces es correcto devolver la excepción a la persona que llama porque es culpa suya. Ignorar silenciosamente la entrada inválida y no hacer nada en el método es un consejo extremadamente pobre porque oculta el problema.
Boann

104
Agregaría un comentario sobre esta publicación que explica que incluso las asignaciones a primitivas pueden causar NPE cuando se usa el autoboxing: int a=bpuede arrojar un NPE si b es un Integer. Hay casos en los que esto es confuso para depurar.
Simon Fischer

58
¿Es posible capturar NPE lanzada por una aplicación web desde el navegador web? Como se mostrará en la fuente de la página de visualización desde el navegador web ..
Sid

76
Sí, compruebe si el objeto es igual a nulo antes de invocar un método o intente acceder a una variable que pueda tener. Algunas veces estructurar su código puede ayudar a evitar una excepción de puntero nulo. por ejemplo, al verificar una cadena de entrada con una cadena constante, debe comenzar con la cadena constante como aquí: if ("SomeString" .equals (inputString)) {} // incluso si inputString es nulo no se produce ninguna excepción. Así que hay muchas cosas que puedes hacer para tratar de estar seguro.
Rose

78
Una forma adicional de evitar 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?)
Arjan Mels

880

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á a NullPointerException. Estos son los más comunes, pero se enumeran otras formas en la NullPointerExceptionpágina de javadoc.

Probablemente el código de ejemplo más rápido que se me ocurrió para ilustrar un NullPointerExceptionsería:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

En la primera línea adentro main , estoy configurando explícitamente elObject referencia objigual a null. 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 un NullPointerExceptionporque 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).


49
Entendí todo lo que escribiste allí, pero solo porque he estado codificando durante un tiempo y sé qué son un 'puntero' y una 'referencia' (y qué es nulo, de hecho). Cuando trato de sumergirme en explicaciones como esa, mis alumnos me miran con los ojos cruzados, porque no hay suficientes antecedentes.
mmr

33
@mmr: Gracias por los comentarios, haces un punto válido. En Internet es difícil juzgar realmente dónde está alguien y a qué nivel es seguro comenzar una explicación. Intentaré revisar esto nuevamente.
Bill the Lizard

22
Una forma más común de obtener una NullPointerException en la práctica sería olvidarse de inicializar explícitamente una variable miembro a algo distinto de 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?
Ilmari Karonen

66
@EJP Creo que sus puntos son válidos, por lo que he actualizado la respuesta para que sea más clara y para evitar decir 'puntos a nulo' donde lo hizo.
Steve Powell el

55
@StevePowell Indiqué hace mucho tiempo que no quería que mi respuesta cambiara. Respeta la intención del autor original.
Bill the Lizard

697

¿Qué es una excepción NullPointerException?

Un buen lugar para comenzar es los JavaDocs . Tienen esto cubierto:

Se lanza cuando una aplicación intenta usar nulo en un caso donde se requiere un objeto. Éstos incluyen:

  • Llamando al método de instancia de un objeto nulo.
  • Acceder o modificar el campo de un objeto nulo.
  • Tomando la longitud de nulo como si fuera una matriz.
  • Acceder o modificar las ranuras de nulo como si fuera una matriz.
  • Lanzamiento nulo como si fuera un valor Lanzable.

Las aplicaciones deberían lanzar instancias de esta clase para indicar otros usos ilegales del objeto nulo.

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 :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • De lo contrario, si el valor de la Expresión es nulo, NullPointerExceptionse arroja a.

¿Cómo lo soluciono?

Entonces tienes un NullPointerException. Como lo arreglas? Tomemos un ejemplo simple que arroja un NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

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:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

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 que ses nulo, y llamar al lengthmétodo en él arroja la excepción. Podemos ver que el programa deja de lanzar la excepción cuando s.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 con printString(name)el print()método y this.namees nulo.

Rastrear dónde deben establecerse estos valores

¿Dónde se this.nameestablece? En el setName(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):

private String name = "";

El método printo printStringpuede verificar nulo , por ejemplo:

printString((name == null) ? "" : name);

O puede diseñar la clase para que name siempre tenga un valor no nulo :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

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 ).


44
+1 Es bueno tener un ejemplo que incluye pasar por el stacktrace; Es importante mostrar por qué leerlo es importante para depurar NPE. (y por qué casi siempre buscamos un seguimiento de pila cuando alguien publica una pregunta sobre un error)
Dennis Meng

16
Usted mencionó la depuración ... ¿Cómo funciona eso? Llevo un tiempo investigando el tema, pero no puedo encontrar nada. ¡Estoy seguro de que un maestro increíble como tú me lo puede enseñar en un segundo! ¡Muchas gracias! :-)
Ruchir Baronia

15
@RuchirBaronia Un depurador le permite recorrer un programa línea por línea para ver qué métodos se llaman y cómo se cambian las variables. Los IDE deberían tener algunas herramientas para hacer esto. Ver vogella.com/tutorials/EclipseDebugging/article.html por ejemplo.
fgb

15
@RuchirBaronia Establece puntos de interrupción en los métodos alrededor de cualquier NullPointerExceptions como se ve en el stacktrace, y verifica los valores de las variables contra lo que espera que sean. Si sabe que una variable es nula cuando no debería serlo, puede establecer puntos de interrupción alrededor de cualquier código que cambie el valor. También hay puntos de interrupción condicionales que puede usar que le indicarán cuándo cambia un valor.
fgb

66
Establecer objetos de cadena en una cadena vacía como su valor predeterminado se considera una mala práctica.
Diminuto

502

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 un nullcomo si fuera una referencia real. Por ejemplo, si escribe esto:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

la declaración etiquetada "AQUÍ" intentará ejecutar el length()método en una nullreferencia, y esto arrojará unNullPointerException .

Hay muchas formas en que podría usar un nullvalor que resultará en a NullPointerException. De hecho, las únicas cosas que puede hacer nullsin causar un NPE son:

  • asignarlo a una variable de referencia o leerlo desde una variable de referencia,
  • asignarlo a un elemento de matriz o leerlo desde un elemento de matriz (¡siempre que la referencia de matriz en sí misma no sea nula!),
  • pasarlo como parámetro o devolverlo como resultado, o
  • probarlo con los ==u !=operadores, o instanceof.

Pregunta: ¿Cómo leo el stacktrace de NPE?

Supongamos que compilo y ejecuto el programa anterior:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

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ándarjavac 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:

Exception in thread "main" java.lang.NullPointerException

La primera línea del seguimiento de la pila te dice varias cosas:

  • Le indica el nombre del hilo de Java en el que se produjo la excepción. Para un programa simple con un hilo (como este), será "principal". Vamonos ...
  • Le dice el nombre completo de la excepción que se produjo; es decir java.lang.NullPointerException.
  • Si la excepción tiene un mensaje de error asociado, se generará después del nombre de la excepción. 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.

at Test.main(Test.java:4)

Esto nos dice una serie de cosas:

  • "at Test.main" dice que estábamos en el mainmétodo de la Testclase.
  • "Test.java:4" proporciona el nombre del archivo fuente de la clase, Y nos dice que la declaración donde ocurrió esto está en la línea 4 del archivo.

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:

int length = foo.length(); // HERE

¿Cómo puede eso arrojar un NPE?

De hecho, solo hay una forma: solo puede suceder si footiene el valor null. Luego intentamos ejecutar el length()método nully ... ¡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.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 .

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

Así que ahora tenemos dos líneas "en". El primero es para esta línea:

return args[pos].length();

y el segundo es para esta línea:

int length = test(foo, 1);

Mirando la primera línea, ¿cómo podría eso arrojar un NPE? Hay dos maneras:

  • Si el valor de bares nullentonces bar[pos]arrojará un NPE.
  • Si el valor de bar[pos]se nullentonces llama length()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 la testllamada al método, y si observamos cómo testse llamó, podemos ver que proviene de la foovariable estática. Además, podemos ver claramente que inicializamos fooa un valor no nulo. Eso es suficiente para descartar provisionalmente esta explicación. (En teoría, algo más podría cambiar foo anull ... pero eso no está sucediendo aquí).

Entonces, ¿qué pasa con nuestro segundo escenario? Bueno, podemos ver que poses 1, lo que significa que foo[1]debe ser null. es posible?

¡De hecho, es! Y ese es el problema. Cuando inicializamos así:

private static String[] foo = new String[2];

asignamos a String[]con dos elementos que se inicializannull . Después de eso, no hemos cambiado el contenido de foo... así foo[1]será null.


426

Es como si estuviera intentando acceder a un objeto que es null. Considere el siguiente ejemplo:

TypeA objA;

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:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

1
Si le damos System.out.println (a.length ()); // Se lanzará NullPointerException, para omitir esto podemos manejarlo con try catch block. gracias
Vijaya Varma Lanke

360

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:

  1. Llamando al método de instancia de un nullobjeto.
  2. Acceder o modificar el campo de un nullobjeto.
  3. Tomando la longitud de nullcomo si fuera una matriz.
  4. Acceder o modificar las ranuras de nullcomo si fuera una matriz.
  5. Lanzando nullcomo 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


12
Que sea simple, me gusta esta respuesta, agregue esto si lo considera correcto - Acceso al atributo no inicializado de un objeto
Emiliano

55
@Emiliano: simplemente acceder a un atributo inicializado no causa un NPE. Es lo que >> hace << con el valor de atributo no inicializado que causa el NPE.
Stephen C

1
Si desea más casos: 1) usando a nullcomo objetivo de un synchronizedbloque, 2) usando a nullcomo objetivo de a switchy unboxing null.
Stephen C

334

Un nullpuntero es aquel que apunta a ninguna parte. Cuando desreferencia un puntero p, dices "dame los datos en la ubicación almacenada en" p ". Cuando pes un nullpuntero, la ubicación almacenada pes nowhere, estás diciendo" dame los datos en la ubicación 'en ninguna parte' ". Obviamente, no puede hacer esto, por lo que arroja un null pointer exception.

En general, es porque algo no se ha inicializado correctamente.


2
¿Estamos creando una base de datos? -> NULLestá escrito como nullen java. Y es algo sensible a mayúsculas y minúsculas.
bvdb

3
"Un puntero NULL es uno que apunta a ninguna parte" No estoy de acuerdo. Los punteros nulos no apuntan a ninguna parte, apuntan a valores nulos.
TheRealChx101

2
@ TheRealChx101 Un puntero nulo y un puntero a un valor nulo son cosas diferentes: un puntero nulo no apunta a un valor nulo. Suponga que tiene un puntero a un puntero: el puntero A apunta al puntero B y el puntero B es nulo. En este caso, el puntero A apunta a un valor nulo, y el puntero B es un puntero nulo.
MrZebra

322

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 Java

Resumen:

  1. Utilizar el final modificador para hacer cumplir una buena inicialización.
  2. Evite devolver valores nulos en los métodos, por ejemplo, devolver colecciones vacías cuando corresponda.
  3. Use anotaciones @NotNully@Nullable
  4. Falla rápidamente y usa afirmaciones para evitar la propagación de objetos nulos a través de toda la aplicación cuando no deberían ser nulos.
  5. Use iguales con un objeto conocido primero: if("knownObject".equals(unknownObject)
  6. Prefiero valueOf()sobre toString().
  7. Use StringUtilsmétodos seguros nulos StringUtils.isEmpty(null).
  8. Use Java 8 Opcional como valor de retorno en los métodos, la clase Opcional proporciona una solución para representar valores opcionales en lugar de referencias nulas.

44
En los proyectos j2ee, la excepción Nullpointer es muy común. En algunos casos, las variables de referencia obtuvieron valores nulos. Por lo tanto, debe verificar la inicialización de la variable correctamente. Y durante la declaración condicional, siempre debe verificar que la marca o referencia contenga nulo o no como: - if (flag! = 0) {su código que usa la bandera}
Amaresh Pattanayak

14
Vale la pena mencionar que algunos IDE (por ejemplo, Eclipse) ofrecen análisis de nulidad automáticos basados ​​en anotaciones personalizables (por ejemplo, @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.
Jan Chimiak

44
Lo primero que debe hacer es antes de usar un objeto anulable, debe verificar si es nulo, usando if (obj==null). Si es nulo, entonces debe escribir código para manejar eso también.
Lakmal Vithanage

44
En mi opinión, es preferible evitar devolver objetos nulos en los métodos cuando sea posible y usar anotaciones cuando no se permitan parámetros de entrada nulos para, por contrato, reducir la cantidad de 'si (obj == nulo)' en el código y mejorar el legibilidad del código.
LG

44
Lea esto ... antes de aceptar estas "mejores prácticas" como verdad: satisfice.com/blog/archives/27
Stephen C

317

En Java, todo (excepto los tipos primitivos) tiene la forma de una clase.

Si desea utilizar cualquier objeto, entonces tiene dos fases:

  1. Declarar
  2. Inicialización

Ejemplo:

  • Declaración: Object object;
  • Inicializacion: object = new Object();

Lo mismo para el concepto de matriz:

  • Declaración: Item item[] = new Item[5];
  • Inicializacion: item[0] = new Item();

Si no está dando la sección de inicialización, entonces NullPointerExceptionsurja.


3
A menudo se produce una NullPointerException cuando se llama al método de una instancia. Por ejemplo, si declara una referencia pero no hace que apunte a ninguna instancia, NullPointerException sucederá cuando llame a su método. tales como: YourClass ref = null; // o ref = anotherRef; // pero anotherRef no ha señalado ninguna instancia ref.someMethod (); // arrojará NullPointerException. En general, corríjalo de esta manera: antes de llamar al método, determine si la referencia es nula. como: if (yourRef! = null) {yourRef.someMethod (); }
sunhang

2
O utilice la captura de excepciones: como: try {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
sunhang


316

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.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

El siguiente código le ofrece una excepción de puntero nulo.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Porque está utilizando student, pero olvidó inicializarlo como en el código correcto que se muestra a continuación:

public class School {

    Student student;

    public School() {
        try {
            student = new Student();
            student.setId(12);
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

77
Si bien este es un buen ejemplo, ¿puedo preguntar qué agrega a la pregunta que no está cubierta por todas las otras respuestas?
Mysticial

13
Es simplemente inapropiado usar la palabra "no inicializado" aquí. De hecho, el ejemplo que mostró está "inicializado" y se inicializa con nulo. Para variables no inicializadas, el compilador se quejará ante usted.
Adrian Shum

2
Un NPE puede ser un indicador de que está utilizando un campo no inicializado. Puede ser un indicador de que está haciendo otras cosas. Simplificar en exceso a una sola causa como esta no ayuda a alguien a resolver problemas de NPE ... si la causa real no es esta.
Stephen C

309

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:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

Y en otro lugar en tu código:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Esta una cosa importante a saber - cuando no hay más referencias a un objeto (en el ejemplo anterior cuando referencey otherReferencetanto 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.


281

Otra ocurrencia de a NullPointerExceptionocurre cuando uno declara una matriz de objetos, e inmediatamente trata de desreferenciar elementos dentro de ella.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

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 sonnull .

Usted debe inicializar los elementos de la matriz antes de acceder o eliminación de referencias a ellos.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

La operación en un objeto no inicializado a nivel de instancia (no a nivel de clase) conducirá a NullPointerException. La operación debe ser específica de la instancia. si la operación está en el nivel de clase, indicando que se llama a un método estático en un objeto no inicializado, no arrojará la excepción NullPointerException. Incluso los objetos de clase de contenedor primitivos arrojan NullPointerException.
Shailendra Singh

1. NullPointerException es una RuntimeException, lo que significa que aparecerá cuando su programa se esté ejecutando, ¡no lo hará en el momento de la compilación! :(, pero la mayoría del IDE lo ayuda a descubrir esto. 2. Minimice el uso de la palabra clave 'nulo' en las declaraciones de asignación. :) URL de referencia:
tomj0101

@ tomj0101 No tengo muy claro por qué hiciste ese comentario ... Pero para tu segundo punto, un patrón anterior Optionalera volver nulo. La palabra clave está bien. Saber cómo protegerse es fundamental. Esto ofrece una ocurrencia común y formas de mitigarlo.
Makoto

NullPointerException es una excepción en tiempo de ejecución que no se recomienda detectar, sino evitarla.
Shomu

2
@Shomu: ¿En qué momento sugiero que sea capturado?
Makoto
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.