Pregunta

Siempre me he preguntado por qué la JVM no le dice que que puntero (o, más exactamente, qué variable) es nula cuando se lanza un NullPointerException.

Un número de línea no es lo suficientemente específica debido a que la línea en cuestión a menudo puede contener numerosas variables que podrían haber causado el error.

¿Hay cualquier compilador o la bandera JVM que haría que estos mensajes de excepción más útil?

¿Fue útil?

Solución

Es porque el desreferenciar siempre sucede cuando no hay ningún nombre disponible. El valor se carga en la pila de operandos, y luego se pasa a uno de los códigos de operación de JRE que elimina referencia a ella. Sin embargo, la pila de operandos no tiene un nombre para asociarlo con un valor nulo. Todo lo que tiene es 'nulo'. Con un poco de tiempo de ejecución de código de seguimiento inteligente, un nombre se puede derivar, pero eso sería una sobrecarga con un valor limitado.

Debido a esto, no hay ninguna opción JRE que se convertirá en la información adicional para las excepciones de puntero nulo.

En este ejemplo, la referencia se almacena en la ranura local de 1, que se asigna a un nombre de variable local. Pero el desreferenciar sucede en la instrucción invokevirtual, que sólo ve un valor 'nulo' en la pila, y luego lanza una excepción:

15 aload_1
16 invokevirtual #5 

igualmente válida sería una carga array seguido de un dereference, pero en este caso no hay ningún nombre para asignar al valor 'nulo', sólo un índice fuera de otro valor.

76 aload    5
78 iconst_0
79 aaload
80 invokevirtual #5

No se puede asignar los nombres de forma estática a cada instrucción, ya sea - este ejemplo produce una gran cantidad de código de bytes, pero se puede ver que la instrucción desreferenciar recibirá ya sea objA o objB, y que tendría que realizar un seguimiento de esta dinámica para informar de la más adecuado, ya que ambas variables de flujo a la misma instrucción eliminar la referencia:

(myflag ? objA : objB).toString()

Otros consejos

Una vez que el código JIT, es simplemente matemáticas puntero nativo, y si alguno de puntero en el código nativo es nulo se produce la excepción. Que tendría un impacto en el rendimiento devastador para revertir esa asamblea de nuevo a la variable original, y teniendo en cuenta el JIT optimiza el código generado a diferentes niveles, a menudo no es aún posible.

Si se rompe la línea en varias líneas en lugar de hacer varias llamadas de método en una sola línea, o si establece un punto de interrupción en esa línea y paso a través de la línea con un depurador, puede averiguar cuál de referencia es nula con bastante facilidad.

Si

  

un número de línea no es lo suficientemente específica   debido a que la línea en cuestión puede a menudo   contienen numerosas variables que pueden   han provocado el error.

entonces sugiero:

  1. Romper esa línea en más de una línea y asignar los valores posibles de generar NullPointerException a variables temporales.
  2. Utiliza un depurador y pasar por encima de cada llamada al método hasta que encuentre el que causa el problema.

Desgraciadamente, esto es sólo la forma en que funciona Java.

Si se trata de "su" código a continuación, sólo tiene que añadir fragmentos como

if (foo == null) {
  throw new NullPointerException("foo == null");
}

justo después de la asignación de foo. Si foo es un parámetro a continuación, comprobar inmediatamente en el inicio del cuerpo del método, y tirar IllegalArgumentException lugar.

Esto debería ayudar a aclarar las cosas.

Puede añadir un punto de interrupción en la excepción de puntero nulo en Eclipse cuando se depura para obtener la causa exacta de la excepción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top