try traducir pointer error catch avoid java nullpointerexception

java - traducir - ¿Qué es una NullPointerException y cómo la soluciono?



nullpointerexception java try catch (12)

¿Qué son las excepciones de puntero nulo ( java.lang.NullPointerException ) y qué las ocasiona?

¿Qué métodos / herramientas se pueden usar para determinar la causa de manera que se evite que la excepción provoque que el programa finalice prematuramente?


En Java, todo está en forma de clase.

Si quieres usar cualquier objeto, entonces tienes dos fases

  1. Declarar
  2. Inicialización

Ejemplo:

  • Declaración: int a;
  • inicialización: a=0;

Lo mismo para el concepto de matriz

  • Declaración: Item i[]=new Item[5];
  • Inicialización: i[0]=new Item();

Si no se le da la sección de Inicialización, entonces NullpointerException la NullpointerException .


Otra aparición de una NullPointerException ocurre cuando uno declara una matriz de objetos, y luego intenta de inmediato desreferenciar los 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 el orden de comparación se invierte; es decir, use .equals en un objeto garantizado no nulo.

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 .

Debe inicializar los elementos en la matriz antes de acceder o eliminarlos.

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


En Java, todas las variables que declaras son en realidad "referencias" a los objetos (o primitivas) y no a los objetos mismos.

Cuando intentas ejecutar un método de objeto, la referencia pide al objeto vivo que ejecute ese método. Pero si la referencia está haciendo referencia a NULL (nada, cero, vacío, nada), entonces no hay forma de que se ejecute el método. 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 la memoria de VM y la única forma de acceder a él es utilizando this referencias. Toma este ejemplo:

public class Some { private int id; public int getId(){ return this.id; } public setId( int newId ) { this.id = newId; } } .... .... // Somewhere else... 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...

Esto es importante de saber: cuando ya no hay más referencias a un objeto (en el ejemplo anterior cuando "referencia" y "otra Referencia" apuntan a nulo), entonces el objeto es "inalcanzable". No hay manera de que podamos trabajar con él, por lo que este objeto está marcado para ser basura recolectada, y en algún momento la máquina virtual liberará la memoria utilizada por este objeto y asignará otra.


Se produce una excepción de puntero nulo cuando se desreferencia una variable que apunta a null . Vea el siguiente código:

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


Un puntero NULL es uno que apunta a ninguna parte. Cuando desreferencia un puntero p , diga "darme los datos en la ubicación almacenada en" p ". Cuando p es un puntero nulo, la ubicación almacenada en p nowhere está en nowhere , usted está diciendo" dame los datos en la ubicación " ''en ninguna parte'' ". Obviamente no puede hacer esto, por lo que arroja una NULL pointer exception .

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


Pregunta: ¿Qué causa una NullPointerException ?

Como debería saber, los tipos de Java se dividen en tipos primitivos ( boolean , int , etc.) y tipos de referencia . Los tipos de referencia en Java le permiten usar el valor especial null que es la forma en Java de decir "sin objeto".

Se lanza una NullPointerException en el tiempo de ejecución cada vez que su programa intenta utilizar un null como 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Í" va a intentar ejecutar el método length() en una referencia null , y esto arrojará una NullPointerException .

Hay muchas formas en que podría usar un valor null que dará como resultado una NullPointerException . De hecho, las únicas cosas que puede hacer con un null sin causar un NPE son:

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

Pregunta: ¿Cómo leo la stack stack de NPE?

Supongamos que compilo y ejecuto el programa de arriba:

$ 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 lanzará siempre una excepción ... pero el compilador javac estándar 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 veamos lo que dice:

Exception in thread "main" java.lang.NullPointerException

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

  • Te dice el nombre del hilo de Java en el que se lanzó la excepción. Para un programa simple con un hilo (como este), será "principal". Vamonos ...
  • Te dice el nombre completo de la excepción que se lanzó; 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. NullPointerException es inusual a este respecto porque raramente 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 cantidad de cosas:

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

Y 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 la traza de la pila NPE. Pero puede estar seguro de que la segunda línea (la primera línea "a") le dirá dónde se lanzó el NPE 1 .

En resumen, stacktrace nos dirá inequívocamente qué afirmación del programa arrojó el NPE.

1 - No del todo cierto. Hay cosas llamadas excepciones anidadas ...

Pregunta: ¿Cómo rastreo 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 relevante de la API.

Primero ilustraremos con el ejemplo simple (arriba). Comenzamos mirando la línea que stacktrace nos dijo dónde ocurrió el NPE:

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

¿Cómo puede eso lanzar un NPE?

De hecho, solo hay una forma: solo puede suceder si foo tiene el valor null . Luego tratamos de ejecutar el método length() en null y .... ¡BANG!

Pero (te oigo decir) ¿qué pasaría si el NPE fuera lanzado dentro del método length() ?

Bueno, si eso sucediera, la stacktrace se vería diferente. La primera línea "at" diría que la excepción fue arrojada en alguna línea en la clase java.lang.String , y la línea 4 de Test.java sería la segunda línea "at".

Entonces, ¿de dónde salió ese null ? En este caso, es obvio y es obvio lo que debemos hacer para solucionarlo. (Asignar un valor no nulo a foo )

OK, intentemos un ejemplo un poco más complicado. Esto requerirá una 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) $

Entonces ahora tenemos 2 líneas "a". El primero es para esta línea:

return args[pos].length();

y el segundo es para esta línea:

int length = test(foo, 1);

Entonces, mirando la primera línea, ¿cómo podría arrojar una NPE? De hecho, hay dos formas:

  • Si el valor de la bar es null , bar[pos] arrojará un NPE.
  • Si el valor de bar[pos] es null , la length() llamada length() arrojará un NPE.

Entonces, tenemos que descubrir cuál de esos escenarios explica lo que realmente está sucediendo. Comencemos explorando el primero:

¿De dónde viene el bar ? Es un parámetro para la llamada al método de test , y si miramos cómo se llamó a la test , podemos ver que proviene de la variable estática foo . Y podemos ver claramente que inicializamos foo a un valor no nulo. Eso es suficiente para descartar tentativamente esta explicación. (En teoría, algo más podría cambiar de foo a null ... pero eso no está sucediendo aquí).

Entonces, ¿qué pasa con nuestro segundo escenario? Bueno, podemos ver que pos es 1 , así que eso significa que foo[1] debe ser null . ¿Es eso posible?

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

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

asignamos un String[] con dos elementos que se inicializan a null . Y luego no cambiamos los contenidos de foo ... así que foo[1] seguirá siendo null .


¿Qué es una NullPointerException?

Un buen lugar para comenzar es el JavaDocs . Ellos tienen esto cubierto:

Lanzado cuando una aplicación intenta usar null en un caso donde se requiere un objeto. Éstas incluyen:

  • Llamar al método de instancia de un objeto nulo.
  • Accediendo o modificando el campo de un objeto nulo.
  • Tomando la longitud de nulo como si fuera una matriz.
  • Accediendo o modificando las ranuras de nulo como si fuera una matriz.
  • Lanzando nulo como si fuera un valor Throwable.

Las aplicaciones deben arrojar instancias de esta clase para indicar otros usos ilegales del objeto nulo.

También es el caso que si intenta utilizar una referencia nula con synchronized , eso arrojará también esta excepción, según el JLS :

SynchronizedStatement: synchronized ( Expression ) Block

  • De lo contrario, si el valor de Expression es nulo, se lanza una NullPointerException .

¿Cómo lo arreglo?

Entonces tienes una NullPointerException , ¿cómo lo arreglas? Tomemos un ejemplo simple que arroja una 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 tenemos que hacer algunas depuraciones. Es importante aprender a leer un stacktrace . Esto le mostrará dónde se lanzó 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 método printString). Mire la línea y compruebe qué valores son nulos agregando declaraciones de registro o utilizando un depurador . Descubrimos que s es nulo y llamar al método de length arroja la excepción. Podemos ver que el programa deja de lanzar la excepción cuando s.length() se elimina del método.

Traza de dónde vienen estos valores

Siguiente verificación de dónde viene este valor. Al seguir a los llamantes del método, vemos que s se pasa con printString(name) en el método print() , y this.name es nulo.

Traza donde estos valores deben ser establecidos

¿Dónde se establece this.name ? En el setName(String) . 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 llaman a estos métodos, y el método set no se llama después del método de impresión.

Esto es suficiente para darnos una solución: agregue una llamada a printer.setName() antes de llamar a printer.print() .

Otras correcciones

La variable puede tener un valor predeterminado (y setName puede evitar que se establezca en nulo):

private String name = "";

El método print o printString puede verificar nulo , por ejemplo:

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

O puede diseñar la clase para que el 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 intentó solucionar el problema y todavía 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 stacktrace en la pregunta y marque los números de línea importantes en el código. Además, intente simplificar primero el código (vea SSCCE ).


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 .

Ver también: una buena lista de mejores prácticas

Yo agregaría, muy importante, hacer un buen uso del modificador final .
Usando el modificador "final" siempre que sea aplicable en java

Resumen:

  1. Use el modificador final para imponer una buena inicialización.
  2. Evite devolver nulos en los métodos, por ejemplo, devolver colecciones vacías cuando corresponda.
  3. Use anotaciones @NotNull y @Nullable
  4. Falla rápido y utiliza 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 el objeto conocido primero: if("knownObject".equals(unknownObject)
  6. Prefiere valueOf() sobre toString ().
  7. Utilice los métodos nulos de StringUtils StringUtils.isEmpty(null) .

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 una int y Java la inicializará a 0 para usted. Cuando lo asigna a 10 en la segunda línea, su valor 10 se escribe en la ubicación de memoria apuntada por x.

Pero, cuando intentas 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 no contiene un valor primitivo. En cambio, contiene un puntero (porque el tipo es Integer que es un tipo de referencia). Como todavía no dijo qué señalar a Java, lo establece en nulo, lo que significa "No estoy apuntando a nada".

En la segunda línea, la new palabra clave se usa para crear una instancia (o crear) un objeto de tipo Entero y la variable de indicador num se asigna a este objeto. Ahora puede hacer referencia al objeto utilizando el operador de desreferenciación . (un punto).

La Exception que solicitó se produce cuando declara una variable pero no crea un objeto. Si intenta desreferencia num ANTES de crear el objeto, obtiene una NullPointerException . En los casos más triviales, el compilador detectará el problema y le informará que "num puede no haberse inicializado", 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 , más bien suponiendo que se creó antes de que se llamara el método doSomething . Desafortunadamente, es posible llamar al método de esta manera:

doSomething(null);

en cuyo caso obj es nulo. Si el método está destinado a hacer algo al objeto pasado, es apropiado lanzar la NullPointerException porque es un error del programador y el programador necesitará esa información para fines de depuración.

Alternativamente, puede haber casos donde el propósito del método no sea únicamente operar en el objeto pasado, y por lo tanto un parámetro nulo puede ser aceptable. En este caso, necesitaría buscar un parámetro nulo y comportarse de manera diferente. También deberías 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 ubicación de la excepción y causar el uso de Stack Trace


NullPointerException s son excepciones que ocurren cuando intenta utilizar una referencia que apunta a ninguna ubicación en la memoria (nulo) como si estuviese 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á una NullPointerException . Estos son los más comunes, pero otras formas se enumeran en la página javadoc NullPointerException .

Probablemente, el código de ejemplo más rápido que podría aparecer para ilustrar una NullPointerException sería:

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

En la primera línea dentro de la principal, estoy estableciendo explícitamente que Object reference es igual 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 un método sobre él. Esto da como resultado una NullPointerException 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 ningún lado , que es sutilmente diferente de apuntando a una ubicación que no es válida.)


Se lanza una excepción de puntero nulo cuando una aplicación intenta usar null en un caso donde se requiere un objeto. Éstas incluyen:

  1. Llamar al método de instancia de un objeto null .
  2. Accediendo o modificando el campo de un objeto null .
  3. Tomando la longitud de null como si fuera una matriz.
  4. Accediendo o modificando las ranuras de null como si fuera una matriz.
  5. Lanzando null como si fuera un valor Throwable.

Las aplicaciones deben arrojar instancias de esta clase para indicar otros usos ilegales del objeto null .

Referencia: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html


Una excepción de puntero nulo es un indicador de que está utilizando Objeto sin inicializarlo.

por ejemplo, a continuación hay una clase de estudiantes que se 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 código siguiente le da una excepción de puntero nulo.

public class School { Student obj_Student; public School() { try { obj_Student.getId(); } catch(Exception e) { System.out.println("Null Pointer "); } } }

Debido a que está utilizando Obj_Student pero olvidó inicializarlo, se muestra a continuación el código correcto.

public class School { Student obj_Student; public School() { try { obj_Student = new Student(); obj_Student.setId(12); obj_Student.getId(); } catch(Exception e) { System.out.println("Null Pointer "); } } }