java - Averigüe qué variable está lanzando una NullPointerException mediante programación
debugging (7)
Sé que puedo descubrir si una variable es nula en Java usando estas técnicas:
- if
(var==null)
-> demasiado trabajo -
try { ... } catch (NullPointerException e) { ...}
-> me dice qué línea está lanzando la excepción - usando el depurador -> a mano, demasiado lento
Considera esta línea de código:
if (this.superSL.items.get(name).getSource().compareTo(VIsualShoppingList.Source_EXTRA)==0) {
Me gustaría saber si hay una forma genérica de averiguar mediante programación qué variable (no solo la línea) está lanzando la NullPointerException en un área determinada de código. En el ejemplo, sabiendo que
¿Qué quiere decir con "usar el depurador -> a mano, demasiado lento"? Si su código está estructurado adecuadamente, entonces no se utilizarán más de dos o tres variables en la misma línea. ¿Es tan lento comprobarlos? No tienes NullPointers cada minuto.
Creo que deberías fijarte en la Ley Demeters .
No hay mucha gente que lo siga estrictamente, porque da lugar a muchos métodos de delegado.
Pero alejarse demasiado de él resultará en dependencias de estructuras internas que deberían ser transparentes.
Desafortunadamente, Java no le mostrará el nombre de la variable o la posición exacta de un error que no sea el número de línea. Si usa Eclipse, puede usar anotaciones anulables, sin embargo, vea http://www.fosslc.org/drupal/content/bye-bye-npe por ejemplo. Ver qué anotación de Java @NotNull debo usar? Para otros sistemas de anotación.
Lo que realmente me ha funcionado de maravilla es capturar la excepción donde normalmente se lanza y luego usar Log para ver si alguno de ellos tiene valores ''nulos''.
Mi código:
try {
if (description_visible) advice_title_cur.setText(all_title_array[pos]);
else advice_title_cur.setText(all_title_array[pos] + "...");
} catch (NullPointerException e) {
e.printStackTrace();
Log.e("My name", "description_visible " + description_visible);
Log.e("My name", "advice_title_cur " + advice_title_cur);
Log.e("My name", "all_title_array " + all_title_array);
Log.e("My name", "pos " + pos);
}
Lo sentimos, no, no hay una forma programática simple de determinar qué variable o método llamada es la fuente de la excepción. Podría usar algo como Programación Orientada a Aspectos (AOP) , por ejemplo, AspectJ , pero esto no es inherente al lenguaje y generalmente no se incorpora a un programa simplemente para fines de depuración.
-
if (var==null) -> too much work
-
try { } catch() { }
-
Debugger
Sé que no quiere escuchar esto, pero estos son simplemente el costo de hacer negocios.
if (this.superSL.items.get(name).getSource().compareTo(VIsualShoppingList.Source_EXTRA)==0) {
Es inusual ver tantas llamadas de método enlazadas. Creo que lo mejor que puede hacer es adquirir el hábito de dividirlos más, no es necesario bajar a 1 llamada por línea, pero menos que esto. ¿Por qué?
1) Correctness
: ¿es válido en el diseño para que una de estas llamadas devuelva nulo? Si es así, debe romperlo, probarlo y manejarlo adecuadamente.
2) Understandability
: sería más fácil para los futuros mantenedores (incluido usted en el futuro ) comprender si intermedias, las variables con nombre para ayudar a aclarar lo que está sucediendo en esta línea.
3) Efficiency
: por lo general, cuando profundiza en un gráfico (encadenando una serie de llamadas a métodos), es probable que tenga que volver a bajar más tarde. Capturar este valor intermedio en una variable intermedia significa evitar hacer una o más llamadas a métodos nuevamente.
4) Debugging
: como lo indica su pregunta, dividir una línea compleja como esta simplifica la depuración. reduciendo la posible fuente de la excepción.
Sé que sugirió que (var==null)
es demasiado trabajo, pero, como dijo Miguel en los comentarios, eso es lo que haría.
Ya que es posible causar una excepción de puntero nulo sin que incluso involucre una variable:
throw new NullPointerException();
Debería decir que no hay una forma genérica de fijar una excepción de puntero nulo a una variable específica.
Su mejor apuesta sería poner el menor número posible de declaraciones en cada línea para que se haga evidente qué causó la excepción del puntero nulo. Considera refactorizar tu código en la pregunta para ver algo como esto:
List items = this.superSL.items;
String name = items.get(name);
String source = name.getSource();
if (source.compareTo(VIsualShoppingList.Source_EXTRA) == 0) {
// ...
}
Es más líneas de código para estar seguro. Pero también es más legible y más fácil de mantener.