Pregunta

Tengo un método de establecimiento simple para una propiedad y null no es apropiado para esta propiedad en particular.Siempre me he sentido desgarrado en esta situación:¿Debería tirar un IllegalArgumentException, o un NullPointerException?Según los javadocs, ambos parecen apropiados.¿Existe algún tipo de estándar entendido?¿O es sólo una de esas cosas que debes hacer como prefieras y ambas son realmente correctas?

¿Fue útil?

Solución

Parece un IllegalArgumentException se llama si no quieres null ser un valor permitido, y el NullPointerException Sería arrojado si intentaras usar una variable que resulta ser null.

Otros consejos

Deberías estar usando IllegalArgumentException (IAE), no NullPointerException (NPE) por las siguientes razones:

Primero el NPE JavaDoc enumera explícitamente los casos en los que la NPE es apropiada.Fíjate que todos están tirados. por el tiempo de ejecución cuando null se utiliza inadecuadamente.En contraste, el IAE JavaDoc No podría ser más claro:"Se arrojó para indicar que se ha aprobado un método un argumento ilegal o inapropiado". ¡Sí, ese eres tú!

En segundo lugar, cuando ve un NPE en un seguimiento de pila, ¿qué supone?Probablemente alguien eliminó la referencia a un null.Cuando ve IAE, asume que la persona que llama al método en la parte superior de la pila pasó un valor ilegal.Una vez más, la última suposición es cierta; la primera es engañosa.

En tercer lugar, dado que IAE está claramente diseñado para validar parámetros, debe asumirlo como la opción de excepción predeterminada, entonces, ¿por qué elegiría NPE en su lugar?Ciertamente no por un comportamiento diferente: ¿realmente espera que el código de llamada detecte NPE por separado de IAE y, como resultado, haga algo diferente?¿Estás intentando comunicar un mensaje de error más específico?Pero puedes hacerlo de todos modos en el texto del mensaje de excepción, como deberías hacer con todos los demás parámetros incorrectos.

Cuarto, todos los demás datos de parámetros incorrectos serán IAE, entonces, ¿por qué no ser coherentes?¿Por qué es ilegal? null ¿Es tan especial que merece una excepción separada de todos los demás tipos de argumentos ilegales?

Finalmente, acepto el argumento dado por otras respuestas de que partes de la API de Java usan NPE de esta manera.Sin embargo, la API de Java es inconsistente con todo, desde tipos de excepción hasta convenciones de nomenclatura, por lo que creo que simplemente copiar ciegamente (su parte favorita) de la API de Java no es un argumento suficientemente bueno para superar estas otras consideraciones.

La norma es tirar el NullPointerException.El generalmente infalible "Java efectivo" analiza esto brevemente en el artículo 42 (primera edición), el artículo 60 (segunda edición) o el artículo 72 (tercera edición) "Favorecer el uso de excepciones estándar":

"Podría decirse que todas las invocaciones de métodos erróneos se reducen a un argumento ilegal o un estado ilegal, pero otras excepciones se utilizan estándar para ciertos tipos de argumentos y estados ilegales.Si una persona que llama pasa nula en algún parámetro para el cual se prohíben los valores nulos, la convención dicta que se lanza NullPointerException en lugar de IllegalArgumentException ".

Yo estaba totalmente a favor de tirar IllegalArgumentException para parámetros nulos, hasta hoy, cuando noté el java.util.Objects.requireNonNull método en Java 7.Con ese método, en lugar de hacer:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

tu puedes hacer:

Objects.requireNonNull(param);

y arrojará un NullPointerException si el parametro que le pasas es null.

Dado que ese método está justo en medio de java.util Considero que su existencia es una indicación bastante clara de que tirar NullPointerException es "la forma Java de hacer las cosas".

Creo que estoy decidido de todos modos.

Tenga en cuenta que los argumentos sobre la depuración estricta son falsos porque, por supuesto, puede proporcionar un mensaje a NullPointerException diciendo qué era nulo y por qué no debería serlo.al igual que con IllegalArgumentException.

Una ventaja adicional de NullPointerException es que, en código de alto rendimiento crítico, se puede prescindir de una comprobación explícita de nulo (y una NullPointerException con un mensaje de error amigable), y simplemente confíe en el NullPointerException obtendrá automáticamente cuando llame a un método en el parámetro nulo.Siempre que llame a un método rápidamente (es decir,falla rápidamente), entonces tienes esencialmente el mismo efecto, solo que no es tan fácil de usar para el desarrollador.La mayoría de las veces probablemente sea mejor verificar explícitamente y lanzar un mensaje útil para indicar qué parámetro era nulo, pero es bueno tener la opción de cambiarlo si el rendimiento lo exige sin romper el contrato publicado del método/constructor.

Tiendo a seguir el diseño de bibliotecas JDK, especialmente Colecciones y Concurrencia (Joshua Bloch, Doug Lea, esos tipos saben cómo diseñar API sólidas).De todos modos, muchas API en el JDK lanzan proactivamente NullPointerException.

Por ejemplo, el Javadoc para Map.containsKey estados:

@throws nullPointerException Si la tecla es nula y este mapa no permite las teclas NULL (opcionales).

Es perfectamente válido lanzar tu propia NPE.La convención es incluir el nombre del parámetro que era nulo en el mensaje de la excepción.

El patrón dice:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

Hagas lo que hagas, no permitas que se establezca un valor incorrecto y genere una excepción más adelante cuando otro código intente usarlo.Eso hace que la depuración sea una pesadilla.Siempre debes seguir el principio de "fallar rápido".

Voté a favor del argumento de Jason Cohen porque estaba bien presentado.Déjame desmembrarlo paso a paso.;-)

  • El NPE JavaDoc dice explícitamente, "otros usos ilegales del objeto nulo".Si se limitara solo a situaciones en las que el tiempo de ejecución encuentra un valor nulo cuando no debería, todos esos casos podrían definirse de manera mucho más sucinta.

  • No puedo evitarlo si asume algo incorrecto, pero suponiendo que la encapsulación se aplique correctamente, realmente no debería importarle ni notar si se eliminó la referencia a un valor nulo de manera inapropiada o no.si un método detectó un nulo inapropiado y desencadenó una excepción.

  • yo elegiría ENP encima IAE por múltiples razones

    • Es más específico sobre la naturaleza de la operación ilegal.
    • La lógica que permite valores nulos por error tiende a ser muy diferente de la lógica que permite valores ilegales por error.Por ejemplo, si estoy validando datos ingresados ​​por un usuario, si obtengo un valor que es inaceptable, la fuente de ese error está en el usuario final de la aplicación.Si obtengo un valor nulo, es un error del programador.
    • Los valores no válidos pueden causar cosas como desbordamientos de pila, errores de falta de memoria, excepciones de análisis, etc.De hecho, la mayoría de los errores generalmente se presentan, en algún momento, como un valor no válido en alguna llamada a un método.Por esta razón veo al IAE como en realidad el LO MÁS GENERAL de todas las excepciones bajo RuntimeException.
  • En realidad, otros argumentos inválidos pueden dar lugar a todo tipo de excepciones. Excepción de host desconocido, Excepción de archivo no encontrado, una variedad de excepciones de errores de sintaxis, Excepción IndexOutOfBounds, fallos de autenticación, etc., etc.

En general, creo que la NPE está muy difamada porque tradicionalmente se ha asociado con código que no sigue las principio de fallo rápido.Eso, además de que el JDK no completó los NPE con una cadena de mensaje, realmente ha creado un fuerte sentimiento negativo que no está bien fundamentado.De hecho, la diferencia entre NPE e IAE desde una perspectiva de tiempo de ejecución es estrictamente el nombre.Desde esa perspectiva, cuanto más preciso seas con el nombre, más claridad le darás a quien llama.

Es una pregunta al estilo de la "Guerra Santa".En otras palabras, ambas alternativas son buenas, pero la gente tendrá sus preferencias y las defenderá a muerte.

si es un setter método y null se le está pasando, creo que tendría más sentido lanzar un IllegalArgumentException.A NullPointerException parece tener más sentido en el caso en el que intentas utilizar realmente el null.

Entonces, si lo estás usando y es null, NullPointer.Si se está pasando y es null, IllegalArgument.

Apache Commons Lang tiene un Excepción de argumento nulo eso hace varias de las cosas discutidas aquí:extiende IllegalArgumentException y su único constructor toma el nombre del argumento que debería haber sido no nulo.

Si bien creo que lanzar algo como NullArgumentException o IllegalArgumentException describe con mayor precisión las circunstancias excepcionales, mis colegas y yo hemos optado por ceder al consejo de Bloch sobre el tema.

No podría estar más de acuerdo con lo que se dice.Fracaso temprano, fracaso rápido.Mantra de excepción bastante bueno.

La pregunta sobre qué excepción lanzar es principalmente una cuestión de gusto personal.En mi opinión, IllegalArgumentException parece más específica que usar un NPE, ya que me dice que el problema estaba en un argumento que pasé al método y no en un valor que pudo haberse generado al ejecutar el método.

Mis 2 centavos

La práctica aceptada es utilizar el IllegalArgumentException (mensaje de cadena) declarar que un parámetro no es válido y dar tantos detalles como sea posible...Entonces, para decir que se encontró que un parámetro es nulo mientras que la excepción no es nula, haría algo como esto:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

Prácticamente no tiene ningún motivo para utilizar implícitamente la "NullPointerException".NullPointerException es una excepción lanzada por la máquina virtual Java cuando intenta ejecutar código en una referencia nula (como Encadenar()).

En realidad, la cuestión de lanzar IllegalArgumentException o NullPointerException es, en mi humilde opinión, sólo una "guerra santa" para una minoría con una comprensión incompleta del manejo de excepciones en Java.En general, las reglas son simples y son las siguientes:

  • Las violaciones de restricciones de argumentos deben indicarse lo más rápido posible (-> fallo rápido), para evitar estados ilegales que son mucho más difíciles de depurar.
  • en caso de un puntero nulo no válido por cualquier motivo, lanza NullPointerException
  • en caso de un índice de matriz/colección ilegal, lanza ArrayIndexOutOfBounds
  • en caso de un tamaño de matriz/colección negativo, lanza NegativeArraySizeException
  • en caso de un argumento ilegal que no esté cubierto por lo anterior y para el cual no tenga otro tipo de excepción más específico, lance IllegalArgumentException como papelera.
  • por otro lado, en caso de una violación de restricción DENTRO DE UN CAMPO que no se pudo evitar mediante un error rápido por alguna razón válida, capture y vuelva a lanzar como IllegalStateException o una excepción marcada más específica.¡Nunca deje pasar la NullPointerException, ArrayIndexOutOfBounds, etc. originales en este caso!

Hay al menos tres muy buenas razones en contra del caso de asignar todo tipo de violaciones de restricciones de argumentos a IllegalArgumentException, y la tercera probablemente sea tan grave como para marcar la práctica como un mal estilo:

(1) Un programador no puede asumir con seguridad que todos los casos de violaciones de restricciones de argumentos resultan en IllegalArgumentException, porque la gran mayoría de las clases estándar usan esta excepción más bien como una papelera si no hay un tipo de excepción más específico disponible.Intentar asignar todos los casos de violaciones de restricciones de argumentos a IllegalArgumentException en su API solo genera frustración en el programador al usar sus clases, ya que las bibliotecas estándar en su mayoría siguen reglas diferentes que violan las suyas, ¡y la mayoría de los usuarios de su API también las usarán!

(2) La asignación de excepciones en realidad da como resultado un tipo diferente de anomalía, causada por una herencia única:Todas las excepciones de Java son clases y, por lo tanto, solo admiten herencia única.Por lo tanto, no hay forma de crear una excepción que sea realmente tanto NullPointerException como IllegalArgumentException, ya que las subclases solo pueden heredar de una u otra.Por lo tanto, lanzar una IllegalArgumentException en caso de un argumento nulo hace que sea más difícil para los usuarios de API distinguir entre problemas cada vez que un programa intenta corregir el problema mediante programación, por ejemplo, ingresando valores predeterminados en una repetición de llamada.

(3) El mapeo en realidad crea el peligro de enmascarar errores:Para mapear violaciones de restricciones de argumentos en IllegalArgumentException, necesitará codificar un try-catch externo dentro de cada método que tenga argumentos restringidos.Sin embargo, simplemente capturar RuntimeException en este bloque catch está fuera de discusión, porque eso corre el riesgo de mapear RuntimeExceptions documentadas lanzadas por métodos libery usados ​​dentro del suyo en IllegalArgumentException, incluso si no son causadas por violaciones de restricciones de argumentos.Por lo tanto, debe ser muy específico, pero incluso ese esfuerzo no lo protege del caso de que accidentalmente asigne una excepción de tiempo de ejecución no documentada de otra API (es decir,un error) en una IllegalArgumentException de su API.Por lo tanto, incluso el mapeo más cuidadoso corre el riesgo de enmascarar errores de programación de otros creadores de bibliotecas como violaciones de restricciones de argumentos de los usuarios de su método, ¡lo cual es simplemente un comportamiento ridículo!

Por otro lado, con la práctica estándar, las reglas siguen siendo simples y las causas de excepción permanecen desenmascaradas y específicas.Para quien llama al método, las reglas también son sencillas:- Si se encuentra con una excepción de tiempo de ejecución documentada de cualquier tipo porque aprobó un valor ilegal, repita la llamada con un valor predeterminado (para estas excepciones específicas es necesaria) o corregir su código, si por otro lado, usted incluye una excepción de tiempo de ejecución que No está documentado que ocurra para un conjunto dado de argumentos, presente un informe de error a los creadores del método para asegurarse de que su código o su documentación se solucionen.

En general, un desarrollador debería nunca lanzar una excepción NullPointerException.El tiempo de ejecución genera esta excepción cuando el código intenta desreferenciar una variable cuyo valor es nulo.Por lo tanto, si su método quiere rechazar explícitamente el valor nulo, en lugar de que simplemente un valor nulo genere una NullPointerException, debe lanzar una IllegalArgumentException.

Lanzar una excepción que es exclusiva de null argumentos (si NullPointerException o un tipo personalizado) hace automatizado null pruebas más confiables.Esta prueba automatizada se puede realizar con reflexión y un conjunto de valores predeterminados, como en Guayaba's NullPointerTester.Por ejemplo, NullPointerTester intentaría llamar al siguiente método...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

...con dos listas de argumentos: "", null y null, ImmutableList.of().Probaría que cada una de estas llamadas arroje el resultado esperado. NullPointerException.Para esta implementación, pasando un null la lista lo hace no producir NullPointerException.Sin embargo, sucede que produce una IllegalArgumentException porque NullPointerTester sucede que usa una cadena predeterminada de "".Si NullPointerTester solo espera NullPointerException para null valores, detecta el error.si espera IllegalArgumentException, lo extraña.

Como pregunta subjetiva, esto debería cerrarse, pero aún está abierto:

Esto es parte de la política interna utilizada en mi lugar de trabajo anterior y funcionó muy bien.Todo esto es de memoria, así que no recuerdo las palabras exactas.Vale la pena señalar que no utilizaron excepciones marcadas, pero eso está más allá del alcance de la pregunta.Las excepciones no controladas que utilizaron se clasificaron en 3 categorías principales.

Excepción de puntero nulo:No tirar intencionalmente.Las NPE solo las debe generar la máquina virtual al eliminar la referencia a una referencia nula.Se deben hacer todos los esfuerzos posibles para garantizar que nunca se arrojen.@Nullable y @NotNull deben usarse junto con herramientas de análisis de código para encontrar estos errores.

Argumento de excepción ilegal:Se lanza cuando un argumento de una función no se ajusta a la documentación pública, de modo que el error pueda identificarse y describirse en términos de los argumentos pasados.La situación del OP entraría en esta categoría.

Excepción de estado ilegal:Se lanza cuando se llama a una función y sus argumentos son inesperados en el momento en que se pasan o son incompatibles con el estado del objeto del que es miembro el método.

Por ejemplo, había dos versiones internas de IndexOutOfBoundsException utilizadas en cosas que tenían una longitud.Una subclase de IllegalStateException, utilizada si el índice era mayor que la longitud.La otra es una subclase de IllegalArgumentException, utilizada si el índice era negativo.Esto se debía a que se podían agregar más elementos al objeto y el argumento sería válido, mientras que un número negativo nunca es válido.

Como dije, este sistema funciona muy bien y fue necesario que alguien explicara por qué existe la distinción:"Dependiendo del tipo de error, es bastante sencillo saber qué hacer.Incluso si no puedes descubrir qué salió mal, puedes descubrir dónde detectar ese error y crear información de depuración adicional".

Excepción de puntero nulo:Maneje el caso nulo o haga una afirmación para que no se descarte el NPE.Si pones una afirmación es sólo uno de los otros dos tipos.Si es posible, continúe depurando como si la afirmación estuviera ahí en primer lugar.

Argumento de excepción ilegal:Tienes algo mal en tu sitio de llamada.Si los valores que se pasan son de otra función, descubra por qué recibe un valor incorrecto.Si está pasando uno de sus argumentos, propague el error y verifique la pila de llamadas hasta que encuentre la función que no devuelve lo que esperaba.

Excepción de estado ilegal:No has llamado a tus funciones en el orden correcto.Si está utilizando uno de sus argumentos, verifíquelo y genere una excepción IllegalArgumentException que describa el problema.Luego puedes propagar las mejillas contra la pila hasta que encuentres el problema.

De todos modos, su punto era que solo puedes copiar IllegalArgumentAssertions en la pila.No hay forma de propagar IllegalStateExceptions o NullPointerExceptions en la pila porque tenían algo que ver con su función.

Quería distinguir los argumentos nulos de otros argumentos ilegales, por lo que derivé una excepción de IAE llamada NullArgumentException.Sin siquiera necesidad de leer el mensaje de excepción, sé que se pasó un argumento nulo a un método y, al leer el mensaje, descubro qué argumento era nulo.Todavía detecto NullArgumentException con un controlador IAE, pero en mis registros es donde puedo ver la diferencia rápidamente.

la dicotomía...¿No se superponen?Sólo las partes de un todo que no se superponen pueden formar una dicotomía.Como yo lo veo:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

Algunas colecciones asumen que null es rechazado usando NullPointerException en vez de IllegalArgumentException.Por ejemplo, si comparas un conjunto que contiene null a un conjunto que rechaza null, el primer set llamará containsAll por el otro y coger su NullPointerException -- pero no IllegalArgumentException.(Estoy mirando la implementación de AbstractSet.equals.)

Se podría argumentar razonablemente que usar excepciones no verificadas de esta manera es un antipatrón, que comparar colecciones que contienen null a colecciones que no pueden contener null es un error probable que realmente debería producir una excepción, o que poner null en una colección es una mala idea.Sin embargo, a menos que estés dispuesto a decir eso equals debería lanzar una excepción en tal caso, estás atascado recordando que NullPointerException es necesario en determinadas circunstancias pero no en otras.("IAE antes de NPE excepto después de 'c'...")

NullPointerException lanzada al intentar acceder a un objeto con una variable de referencia cuyo valor actual es nulo

IllegalArgumentException lanzada cuando un método recibe un argumento con un formato diferente al esperado

Según su escenario, IllegalArgumentException es la mejor elección, porque null no es un valor válido para su propiedad.

Lo ideal sería no lanzar excepciones en tiempo de ejecución.Se debe crear una excepción marcada (excepción comercial) para su escenario.Porque si cualquiera de estas excepciones se lanza y se registra, desvía al desarrollador al revisar los registros.En cambio, las excepciones comerciales no crean ese pánico y, por lo general, se ignoran al solucionar problemas de los registros.

Las definiciones de los enlaces a las dos excepciones anteriores son ilegalargumentException:Se lanza para indicar que a un método se le ha pasado un argumento ilegal o inapropiado.Excepción de puntero nulo:Se lanza cuando una aplicación intenta usar null en un caso en el que se requiere un objeto.

La gran diferencia aquí es que se supone que IllegalArgumentException se usa al verificar que un argumento de un método es válido.Se supone que NullPointerException se usa siempre que se "usa" un objeto cuando es nulo.

Espero que eso ayude a poner a los dos en perspectiva.

Si se trata de un "configurador", o en algún lugar donde conseguiré que un miembro lo use más adelante, tiendo a usar IllegalArgumentException.

Si es algo que voy a usar (desreferenciar) ahora mismo en el método, lanzo una NullPointerException de forma proactiva.Me gusta más esto que dejar que el tiempo de ejecución lo haga, porque puedo proporcionar un mensaje útil (parece que el tiempo de ejecución también podría hacer esto, pero eso es una perorata para otro día).

Si estoy anulando un método, uso lo que utilice el método anulado.

Deberías lanzar una IllegalArgumentException, ya que le hará evidente al programador que ha hecho algo no válido.Los desarrolladores están tan acostumbrados a ver NPE lanzado por la VM, que cualquier programador no se daría cuenta inmediatamente de su error y comenzaría a buscar aleatoriamente, o peor aún, culparía a su código por tener "errores".

En este caso, IllegalArgumentException transmite información clara al usuario que utiliza su API de que "no debe ser nulo".Como señalaron otros usuarios del foro, puede usar NPE si lo desea, siempre que transmita la información correcta al usuario que utiliza su API.

GaryF y tweakt eliminaron referencias de "Java efectivo" (que juro) que recomiendan el uso de NPE.Y observar cómo se construyen otras API buenas es la mejor manera de ver cómo construir su API.

Otro buen ejemplo es mirar las API de Spring.Por ejemplo, org.springframework.beans.BeanUtils.instantiateClass(Constructor ctor, Object[] args) tiene una línea Assert.notNull(ctor, "Constructor must not be null").El método org.springframework.util.Assert.notNull(Object object, String message) comprueba si el argumento (objeto) pasado es nulo y, si lo es, genera una nueva IllegalArgumentException(message) que luego se captura en la organización. método springframework.beans.BeanUtils.instantiateClass(...).

Si elige generar una NPE y está utilizando el argumento en su método, puede resultar redundante y costoso verificar explícitamente un valor nulo.Creo que la VM ya lo hace por ti.

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