¿Está bien lanzar NullPointerException programáticamente?

Cuando hay una condición posterior, ese valor de retorno de un método no debe ser nulo, ¿qué se puede hacer?

Yo podría hacer

assert returnValue != null : "Not acceptable null value"; 

¡pero las afirmaciones podrían desactivarse!

Entonces, ¿está bien hacer

 if(returnValue==null) { throw new NullPointerException("return value is null at method AAA"); } 

?

¿O es mejor usar una excepción definida por el usuario (como NullReturnValueException) para tal condición?

No veo ningún problema para lanzar una NPE lo antes posible antes de que la JVM lo haga por usted, en particular para argumentos nulos. Parece haber cierto debate sobre esto, pero hay muchos ejemplos en las bibliotecas Java SE que hacen exactamente esto. No puedo entender por qué la NPE debe ser sagrada en el aspecto de que no puedes arrojarla tú mismo.

Sin embargo, estoy divagando. Esta pregunta es sobre algo diferente. Está hablando de una condición posterior que establece que el valor de retorno no debe ser nulo. ¿Seguro que nulo en este caso significaría que tienes un error dentro del mismo método ?

¿Cómo documentarías esto? “Este método arroja una NullPointerException si el valor de retorno inesperadamente es nulo”? Sin explicar cómo podría pasar esto? No, usaría una afirmación aquí. Las excepciones se deben usar para errores que puedan ocurrir, no para cubrir cosas que pueden suceder si hay algo mal dentro del método, porque eso no ayuda a nadie.

Yo recomendaría que nunca NullPointerException por ti mismo.

La razón principal para no hacer esto, como dice Thorbjørn Ravn Andersen en un comentario a continuación, es que no desea mezclar “NPE reales, malos” con NPE arrojados intencionalmente.

Por lo tanto, hasta que esté seguro de que puede reconocer el NPE “válido”, le recomendaría usar IllegalArgumentException cuando quiera decirle a su usuario de API que null no es un valor de argumento válido. Debe documentarse el comportamiento de su método cuando se pasa un parámetro nulo ilegal.

Otra opción (más moderna) es usar la anotación @NotNull cerca del argumento. Aquí hay un artículo sobre el uso de la anotación @NotNull .

Como mencioné anteriormente, también puede haber casos en los que lanzar NPE no te confunda ni a ti ni a tus compañeros de equipo: la causa de NPE debe ser clara y reconocible.

Por ejemplo, si utiliza alguna biblioteca con un módulo de condiciones previas, como Guava , entonces me parece que usar métodos como checkNotNull() es una forma preferible de lidiar con nulos pasados ​​ilegalmente.

checkNotNull(arg, msg) arroja NPE, pero desde la stack está bastante claro, que fue producido por Preconditions.checkNotNull() y, por lo tanto, no es un error desconocido, sino un comportamiento esperado.

Dado que NullPointerException es la forma idiomática de comunicar un valor nulo inesperado en Java, recomendaría que arrojes una NullPointerException estándar y no una local. También tenga en cuenta que el principio de menor sorpresa sugeriría que no invente su propio tipo de excepción para un caso donde exista un tipo de excepción del sistema.

Las afirmaciones son buenas para la depuración pero no son buenas si tienes que manejar ciertas condiciones, por lo que no es una buena forma de manejar la condición de error.

El problema con NullPointerException es que se produce cuando se olvida de verificar si algo es nulo o da el argumento incorrecto que es nulo, y no debería.

Desde mi experiencia, los progtwigdores de Java aprenden muy rápidamente que esta excepción es causada por el error en el código, por lo que lanzarlo manualmente será extremadamente confuso para la mayoría de ellos. IllegalArgumentException es una mejor idea cuando pasas un argumento inaceptable (como null, donde algo no debe ser nulo).

Desencadena también otra heurística. NPE = alguien cometió un error en el código aquí, IllegalArgumentException = el objeto dado al método no es válido.

Por otro lado, el javadoc dice:

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

Así que lanzar NPE sería legal , sin embargo, no es una práctica común, por lo que recomendaría IllegalArgumentException .

Ciertamente, no existe una ley universal contra el lanzamiento de NullPointerException, pero es difícil responder si realmente se debe en un ejemplo tan abstracto. Lo que no quieres hacer es poner a la gente en la cadena en la posición de tratar de atrapar NullPointerException. Código como este (ejemplo real, lo juro):

 catch (NullPointerException npe) { if (npe.getMessage().equals("Null return value from getProdByCode") { drawToUser("Unable to find a product for the product type code you entered"); } } 

Es un indicador seguro de que estás haciendo algo mal. Entonces, si el valor de retorno nulo es un indicador de algún estado del sistema que usted realmente puede comunicar, use una excepción que comunique ese estado. No hay muchos casos en los que pueda pensar que tenga sentido anular una referencia solo para arrojar un nullpointer. Por lo general, la siguiente línea de código habría arrojado al nullpointer (¡o algo más informativo) de todos modos!

Consideraría que el uso de NullPointerException está bien, si recuerda la descripción. Eso es con lo que la persona que investiga trabaja (los números de línea pueden cambiar). Recuerde también documentar que sus métodos arrojan excepciones de puntero nulo en casos especiales.

Si comprueba los parámetros de su método al principio, también es aceptable una throw new IllegalArgumentException("foo==null") .

El JavaDoc para estados NullPointerException :

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

 * Calling the instance method of a null object. * Accessing or modifying the field of a null object. * Taking the length of null as if it were an array. * Accessing or modifying the slots of null as if it were an array. * Throwing null as if it were a Throwable value. 

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

Considero que la violación de la condición posterior es una acción ilegal. Sin embargo, creo que la excepción que uses no importa mucho, porque estamos hablando de una ruta de código que debería (y afortunadamente) es inalcanzable, y por lo tanto no tendrás un manejo de error específico para esa excepción, y por lo tanto, el único efecto de ese nombre es una redacción diferente de alguna entrada en un archivo de registro que nadie verá nunca.

Si, por el contrario, cree que es probable que se viole la condición de la publicación, podría ser una buena idea incluir más información de depuración, como los argumentos con los que se invocó el método.

Si describe un contrato de método donde el valor de retorno no puede ser null , entonces es mejor que se asegure de no devolver null . Pero esta no es una NullPointerException en absoluto. Si el valor que debe devolver es null es evidente que la persona que llama le ha dado malos argumentos ( IllegalArgumentException ), no se encuentra en un estado válido ( IllegalStateException ), o alguna otra condición excepcional mucho más significativa que NullPointerException (que generalmente indica un error de progtwigción).

http://pmd.sourceforge.net/pmd-5.0.1/rules/java/strictexception.html
“Evite lanzar NullPointerExceptions. Estos son confusos porque la mayoría de la gente supondrá que la máquina virtual lo lanzó. Considere usar una IllegalArgumentException en su lugar, esto se verá claramente como una excepción iniciada por el progtwigdor”.

Un libro que he llamado O’Reilly’s Java in A Nutshell, que está escrito por un experto, enumera esta definición para NullPointerException:

Señala un bash de acceder a un campo o invocar un método de un objeto nulo.

Como devolver null no es una de esas cosas, creo que sería más apropiado escribir tu propia excepción.

A menudo es una muy buena idea lanzar NPE antes de que la lógica sea tan profunda que el progtwigdor que llama tendrá dificultades para descubrir qué fue nulo. Los métodos addListener () son un buen ejemplo.

A pesar de los votos bajos no informados, hay muchos métodos en el JDK que hacen exactamente esto.

IMO nunca debe lanzar manualmente una NullPointerException. La rutina de llamada no sabría si la NullPointerException real o manual sin verificar la descripción. En este caso, parece que desea lanzar su propia excepción que coincida con el problema, para que el método de llamada pueda recuperar correctamente esta excepción. Tal vez una PostConditionException sería lo suficientemente genérica para muchas circunstancias.

En Java-verse, null es siempre un valor válido cuando se espera un objeto. Será mejor que evites esas condiciones de publicación imposibles. Si realmente no puedes soportar un nulo, entonces tendrás que volver a trabajar tu método para que puedas devolver un primitivo.

Como dijo Joshua Bloch una vez: “¡Nulo apesta!” 🙂 siempre que haya nulo mi cara, trato de usar el Opcional que proporciona la guayaba. Las ventajas son numerosas para mí.

Absolutamente sí.

Incluso JDK7 resolver esto. Ver objetos # requireNonNull

 void doWith(final Object mustBeNotNull) { /* // bush style if (mustBeNotNull == null) { throw new IllegalArgumentException("mustBeNotNull must not be null"); } */ /* // obama style if (mustBeNotNull == null) { throw new NullPointerException("mustBeNotNull must not be null"); } */ // kangnam style Objects.requireNonNull(mustBeNotNull, "mustBeNotNull must not be null"); assert mustBeNotNull != null; } 

Cuando hay una condición posterior, ese valor de retorno de un método no debe ser nulo, ¿qué se puede hacer?

Una condición posterior significa que el método en cuestión tiene un error si la condición no se cumple. La forma de express esto en código es mediante el uso de una assert en la condición posterior. IllegalStateException directamente una excepción, como una NullPointerException o una IllegalStateException , sería un poco erróneo y, por lo tanto, erróneo.

¿Está bien lanzar NullPointerException programáticamente?

El documento de la API de Java para la NPE dice que sí, pero, a juzgar por los votos dados en esta página, una mayoría de desarrolladores de 3: 1 dice que no. Entonces yo diría que depende de las convenciones en su grupo de trabajo.

El doc API primero enumera los casos en que la JVM genera un NPE porque el código intenta invocar una operación en una referencia nula que requiere un tipo de objeto (como llamar a un método o acceder a un campo) y null no es un objeto. Luego dice:

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

Curiosamente, null se llama un “objeto” aquí, que no lo es. Lo que me recuerda que el mismo nombre NullPointerException es extraño para un lenguaje que no tiene punteros. (Probablemente debería haber sido NullReferenceException como en la biblioteca de clases de Microsoft .NET).

Entonces, ¿deberíamos descartar el doc API en este conteo? No lo creo. La biblioteca de clases usa el NPE como se describe en los documentos, por ejemplo en java.nio.channels :

A menos que se indique lo contrario, pasar un argumento null a un constructor o método en cualquier clase o interfaz en este paquete provocará que se NullPointerException una NullPointerException .

Esto no es un NPE generado por la JVM, sino un NPE codificado con un mensaje de error adjunto que indica qué argumento era null (como "in" is null! ). (El código se puede ver haciendo javap -c -p java.nio.channels.Channels | more , buscando private static void checkNotNull .) Y hay muchas clases que usan NPE de esta manera, esencialmente como un caso especial de IllegalArgumentException .

Así que después de investigar esto un poco y pensar en ello, considero que es un buen uso de la NPE, y por lo tanto, estoy de acuerdo con el doc API y la minoría de desarrolladores de Java (según los votos en esta página) que ambos son derecho y derecho a usar el NPE en su propio código de la misma forma que lo hace la biblioteca de clases Java, es decir, proporcionando un mensaje de error, que shinymente falta en los NPE generados por JVM, por lo que no hay problema para decir los dos tipos de NPE aparte.

Para abordar el punto menor de que el NPE se lanzará de todos modos más adelante: puede tener sentido detectar los errores anticipadamente en lugar de permitir que la JVM continúe con el progtwig, posiblemente con E / S de disco o red (y retrasos ), y generar una traza de stack innecesariamente grande.

Sí, está bien, pero yo diría que es una mejor decisión dejar que ocurra .

El problema con los progtwigdores de Java es que las personas provienen de un fondo de C / C ++, donde NULL significa algo muy diferente. En C / C ++ la eliminación de referencias a un puntero NULO (o desenfrenado) es un problema grave que puede causar problemas de memoria extraños o bloquear su progtwig (obviamente no es deseable). Si puede salir de la forma de pensar de C / C ++ y se da cuenta de que tiene esta capa adicional, la JVM, que maneja esta condición para usted, comienza a pensar en NULL de forma un poco diferente.

En C ++ tenemos referencias, por ejemplo, que nunca se pueden asignar a NULL. En Java, no hay referencias, pero los parámetros del objeto Java se comportan más como punteros C ++. ¡Pero hay muchas situaciones en Java en las que un método NO debería recibir implícitamente un valor nulo para un parámetro! ¿Asi que que hacemos?

El problema con tratar null en Java como lo hace en C ++ es que esto da como resultado comprobaciones nulas en TODAS PARTES , mientras que en C ++ simplemente estaría declarando un método para tomar una referencia, que explícitamente indica que no acepta NULL. Muy pronto, todos los métodos deben tener un control de cordura solo para afirmar la condición del progtwig en ese punto, creando un desorden.

Es un estado de ánimo mucho mejor trabajar bajo la suposición de que el contrato predeterminado de un método es que nulo no es válido para un valor de parámetro.

¿Por qué? Bueno, veamos qué sucede cuando tal método recibe nulo como valor de parámetro. a) Quizás esté bien porque no desreferencia el valor como parte de su comportamiento. En este caso, no pasa nada. b) El valor es desreferenciado. En este caso, el comportamiento de la JVM es exactamente lo que deseamos: se lanza una excepción que indica que el contrato del método ha sido violado debido a que el valor de un parámetro es nulo e incluye un seguimiento de la stack que nos lleva hasta el final. línea en el método donde el valor se utiliza de esta manera.

La gente tiene problemas con NPE porque piensan que cuando ves NPE en los registros, significa “alguien jodido”. Pero pensemos en esto por un segundo. ¿Cuál es en realidad la diferencia en NPE como un indicador de embrutecimiento en comparación con el comportamiento esperado? Yo diría que la principal diferencia (y ventaja) del uso de NPE como comportamiento esperado es que no apunta al método en el que ocurrió, sino a la persona que llama por violar el contrato del método. Esta es una información mucho más útil. Si simplemente verificásemos nulo y lanzáramos una excepción diferente, podríamos tener la falsa impresión de que el comportamiento observado es un error esperado, cuando en realidad la persona que llama viola el contrato del método. Enhorabuena, anticipó correctamente cómo la persona que llama podría estropear al llamar al método; sin embargo, todo lo que hizo se desvió de la causa real de la excepción, o, en el mejor de los casos, está utilizando dos clases de excepciones diferentes. para indicar lo mismo y ensuciar masivamente el código con basura innecesaria mientras tanto.

Entonces, cuando se trata de eso, la gente considera que NPE es tabú. Literalmente, la gente no permitirá que se lance porque hay una sensación de vergüenza que la acompaña, como si no fuera lo suficientemente inteligente porque no pudo adivinar dónde sería nulo un valor. Bueno, tengo noticias para ustedes, solo escriben código más inútil para hacer lo mismo.

Algunos ejemplos:

 public void foo(Object o) { if (o == null) { throw new IGotchaException("HA! You're an IDIOT! I knew it!!"); } o.bar(); } public void foo(Object o) { o.bar(); } 

^ Políticamente diferente. Funcionalmente, no tanto.

 public void foo(int a, long b, double c, Object o) { if (o == null) { throw new IllegalArgumentException("Oh. Uh. Well, you've passed me null here. I... I'm not sure where to go from here because this object is kind of required for this function to do what it's supposed to do. Soooo... wouldja mind reworking your code a little bit so as to not pass null to this function as a parameter?! That'd be great thanks. Oh by the way, it's cause we deference o 40 lines below here"); } // ... o.doSomethingWithA(a); } public void foo(int a, long b, double c, Object o) { // ... o.doSomethingWithA(a); // NullPointerException, line 40, eg it wasn't OK to pass null for o you lunkhead } 

^ Tal vez ahorre algunos ciclos de CPU a expensas de un montón de código molesto. Sin embargo, hacemos menos comparaciones en el segundo caso.

 public void foo(Object a, Object b, Object c, Object d) { if (a == null) throw IllegalArgumentException("jackass"); if (b == null) throw IllegalArgumentException("jackass"); if (c == null) throw IllegalArgumentException("jackass"); // But d is totally OK! // ... c.setSomeValueThatMayBeNull(d); } public void foo(Object a, Object b, Object c, Object d) { // ... c.setSomeValueThatMayBeNull(d); // Throws null pointer exception if c is null, but not if d is null. Which is basically the same as above } 

^ El contrato está implícito en la statement, en lugar de un caso de excepción al comienzo del método. No ofrece ninguna otra desventaja.

 public void foo(Object o) { if (o == null) { doTheBoogie(); } else { doTheRobot(); } } 

^ Malo

 public void foo(Object o, int b) { Bar value = o.findSomethingWhichMayExist(b); if (value == null) return; value.doSomething(); } 

^ Usar valor de retorno nulo para indicar la ausencia de un valor. DE ACUERDO.

Otra razón por la que las personas tienen problemas con NPE es porque no saben cómo manejar las excepciones. La NPE nunca debería ser un disparate. El comportamiento apropiado es atrapar RuntimeException, presumiblemente a un nivel mucho más alto (o más bajo, según cómo lo vea) en la stack de llamadas que lo atrapa e informa antes de “principal”. Es decir, suponiendo que está desarrollando el tipo de progtwig que necesita ser más resistente y no puede bloquearse cuando ocurre una NPE.

En pocas palabras: nunca espere que sea válido pasar valores nulos para los parámetros del método. Y definitivamente no cree un contrato para un método que acepte nulo explícitamente y lo trate como un valor válido. Pero permita que sucedan excepciones de puntero nulo y deje que el código falle o no falle cuando no importe, naturalmente.

Estoy de acuerdo con el reclamo en las respuestas anteriores, que el NPE es un error en el código y no debe arrojarse, pero el desarrollador debe corregir el nulo inesperado. Sin embargo, este estado se puede evitar la mayor parte del tiempo mediante pruebas.

La pregunta fue hecha antes de los 7 años, pero ahora tenemos Opcional en Java 8 y esta característica permite prevenir NPE.

La última solución, que tengo en mente es que debes verificar el objeto en nulo y si es igual, así que emite tu propia excepción con una descripción de lo que sucedió.

Elijo que la excepción no es una buena práctica en algún caso y me pregunto por qué cuando ya la pillas con la statement if.

if (returnValue == null)