Pregunta

Si recibo una NullPointerException en una llamada como esta:

someObject.getSomething().getSomethingElse().
    getAnotherThing().getYetAnotherObject().getValue();

Recibo un texto de excepción bastante inútil como:

Exception in thread "main" java.lang.NullPointerException
at package.SomeClass.someMethod(SomeClass.java:12)

Me resulta bastante difícil descubrir qué llama realmente returend null, a menudo me encuentro refactorizando el código a algo como esto:

Foo ret1 = someObject.getSomething();
Bar ret2 = ret1.getSomethingElse();
Baz ret3 = ret2.getAnotherThing();
Bam ret4 = ret3.getYetAnotherOject();
int ret5 = ret4.getValue();

y luego esperando una NullPointerException más descriptiva que me diga qué línea buscar.

Algunos de ustedes podrían argumentar que concatenar a los captadores es un mal estilo y debería evitarse de todos modos, pero mi pregunta es: ¿Puedo encontrar el error sin cambiar el código?

Sugerencia: estoy usando eclipse y sé lo que es un depurador, pero no puedo averiguar cómo aplicarlo al problema.

Mi conclusión sobre las respuestas:
Algunas respuestas me dijeron que no debería encadenar a los captadores uno tras otro, algunas respuestas me mostraron cómo depurar mi código si no cumplía con ese consejo.

He aceptado una respuesta que me enseñó exactamente cuándo encadenar a los captadores:

  • Si no pueden devolver nulo, encadenarlos el tiempo que desee. ¡No es necesario verificar! = Nulo, no hay que preocuparse por NullPointerExceptions ( tenga en cuenta que el encadenamiento todavía contiene la ley de demeter, pero puedo vivir con eso )
  • Si pueden devolver nulo, nunca, nunca los encadene, y realice una comprobación de valores nulos en cada uno que pueda devolver nulo

Esto hace que cualquier buen consejo sobre la depuración real sea inútil.

¿Fue útil?

Solución

La respuesta depende de cómo veas (el contrato de) tus captadores. Si pueden devolver null , realmente debería verificar el valor de retorno cada vez. Si el getter no debe devolver null , el getter debe contener un cheque y lanzar una excepción ( IllegalStateException ?) En lugar de devolver null , que usted Prometió nunca volver. El stacktrace te indicará el getter exacto. Incluso podría poner el estado inesperado que encontró su captador en el mensaje de excepción.

Otros consejos

NPE es la excepción más inútil en Java, punto. Parece que siempre se implementa de manera perezosa y nunca dice exactamente qué lo causó, incluso si la clase x.y.Z es nula. ayudaría mucho a depurar estos casos.

De todos modos, la única buena manera que he encontrado para encontrar el lanzador de NPE en estos casos es el siguiente tipo de refactorización:

someObject.getSomething()
          .getSomethingElse()
          .getAnotherThing()
          .getYetAnotherObject()
          .getValue();

Ahí lo tienes, ahora NPE apunta a la línea correcta y, por lo tanto, al método correcto que arrojó el NPE real. No es una solución tan elegante como me gustaría que fuera, pero funciona.

En IntelliJ IDEA puede establecer puntos de interrupción de excepción . Esos puntos de interrupción se activan cada vez que se produce una excepción específica (puede incluir esto en un paquete o una clase).

De esa manera debería ser fácil encontrar la fuente de su NPE.

Supongo que puedes hacer algo similar en netbeans o eclipse.

EDITAR: Aquí hay una explicación sobre cómo agregar un punto de ruptura de excepción en eclipse

Si te encuentras escribiendo a menudo:

a.getB().getC().getD().getE();

este es probablemente un olor a código y debe evitarse. Puede refactorizar, por ejemplo, en a.getE () que llama a b.getE () que llama a c.getE () que llama d.getE () . (Este ejemplo puede no tener sentido para su caso de uso particular, pero es un patrón para arreglar este olor a código).

Consulte también la Ley de Demeter , que dice:

  • Su método puede llamar a otros métodos en su clase directamente
  • Su método puede invocar métodos en sus propios campos directamente (pero no en los campos de los campos)
  • Cuando su método toma parámetros, su método puede llamar métodos directamente sobre esos parámetros.
  • Cuando su método crea objetos locales, ese método puede invocar métodos en los objetos locales.

Por lo tanto, uno no debe tener una cadena de mensajes, p. a.getB (). getC (). doSomething () . Siguiendo esta "ley" tiene muchos más beneficios además de hacer que NullPointerExceptions sea más fácil de depurar.

Por lo general, no encadena a captadores como este donde hay más de un captador anulable.

Si está ejecutando dentro de su ide, simplemente puede establecer un punto de interrupción y usar la expresión "evaluar" funcionalidad de su ide en cada elemento sucesivamente.

Pero se rascará la cabeza en el momento en que reciba este mensaje de error de los registros de su servidor de producción. Así que mejor conserve un máximo de un elemento anulable por línea.

Mientras tanto, podemos soñar con operador de navegación segura de groovy

La falla temprana también es una opción.

En cualquier parte de su código que se pueda devolver un valor nulo, considere introducir un cheque para un valor de retorno nulo.

public Foo getSomething()
{
  Foo result;
  ...
  if (result == null) {
    throw new IllegalStateException("Something is missing");
  }
  return result;
}

Aquí se explica cómo encontrar el error, utilizando Eclipse.

Primero, establezca un punto de interrupción en la línea:

someObject.getSomething().getSomethingElse().
getAnotherThing().getYetAnotherObject().getValue();

Ejecute el programa en modo de depuración, permita que el depurador cambie a su perspectiva cuando se golpee la línea.

Ahora, resalte " someObject " y presione CTRL + MAYÚS + I (o haga clic con el botón derecho y diga "inspeccionar").

¿Es nulo? Has encontrado tu NPE. ¿No es nulo? Luego resalte someObject.getSomething () (incluido el paréntesis) e inspecciónelo. ¿Es nulo? Etc. Continúe por la cadena para averiguar dónde está ocurriendo su NPE, sin tener que cambiar su código.

Puede consultar esta pregunta sobre cómo evitar! = null .

Básicamente, si nulo es una respuesta válida, debe verificarla. Si no, afirmarlo (si puedes). Pero haga lo que haga, intente minimizar los casos en los que nulo es una respuesta válida por esto, entre otras razones.

Si tiene que llegar al punto en el que está dividiendo la línea o haciendo una depuración elaborada para detectar el problema, entonces esa es generalmente la forma en que Dios le dice que su código no está verificando el nulo lo suficientemente temprano .

Si tiene un método o un constructor que toma un parámetro de objeto y el objeto / método en cuestión no puede tratar de manera sensata que ese parámetro sea nulo, entonces simplemente verifique y arroje una NullPointerException allí y luego.

He visto a personas inventar " estilo de codificación " reglas para tratar de solucionar este problema, como "no se le permite más de un punto en una línea". Pero esto solo alienta la programación que detecta el error en el lugar equivocado.

Expresiones encadenadas como esa son difíciles de depurar para NullPointerExceptions (y la mayoría de los otros problemas que pueden ocurrir), por lo que le aconsejaría que intente evitarlo. Sin embargo, es probable que haya escuchado eso lo suficiente y, como en un póster anterior mencionado, puede agregar puntos de interrupción en la NullPointerException real para ver dónde ocurrió.

En eclipse (y la mayoría de los IDE) también puede usar expresiones de observación para evaluar el código que se ejecuta en el depurador. Haces esto seleccionando el código y usando el menú de contet para agregar un nuevo reloj.

Si tiene el control del método que devuelve nulo, también podría considerar el patrón Objeto nulo si nulo es un valor válido para devolver.

Coloque cada captador en su propia línea y depure. Pase sobre (F6) cada método para encontrar qué llamada devuelve nulo

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