IllegalArgumentException o NullPointerException para un parámetro nulo? [cerrado]

547

Tengo un método de establecimiento simple para una propiedad y nullno es apropiado para esta propiedad en particular. Siempre me he desgarrado en esta situación: ¿debería tirar un IllegalArgumentExceptiono un NullPointerException? De los javadocs, ambos parecen apropiados. ¿Hay algún tipo de estándar entendido? ¿O es solo una de esas cosas que debes hacer lo que prefieras y ambas son realmente correctas?

Mike Stone
fuente

Respuestas:

299

Parece que se requiere un IllegalArgumentExceptionsi no desea nullser un valor permitido, y se NullPointerExceptiongeneraría si intentara usar una variable que resulta ser null.

Greg Hurlman
fuente
33
Las siguientes respuestas a esta pregunta presentan argumentos persuasivos de que NullPointerException es la excepción correcta: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; y stackoverflow.com/a/6358/372926 .
SamStephens
2
IllegalArgumentExceptionestá en contradicción con los Objects.requireNonNull (T) de Java y las Precondiciones de Guavas.checkNotNull (T) que arroja a NullPointerException. Sin embargo, la respuesta correcta es definitiva IllegalArgumentException como se explica en la excelente respuesta de Jason Cohen y su sección de comentarios .
matoni
417

Debería usar IllegalArgumentException(IAE), no NullPointerException(NPE) por las siguientes razones:

Primero, el NPE JavaDoc enumera explícitamente los casos en los que el NPE es apropiado. Tenga en cuenta que todos ellos son lanzados por el tiempo de ejecución cuando nullse usa de manera inapropiada. Por el contrario, el IAE JavaDoc no podría ser más claro: "Lanzado para indicar que un método ha pasado un argumento ilegal o inapropiado". Sí, ese eres tú!

En segundo lugar, cuando ve un NPE en una traza de pila, ¿qué supone? Probablemente que alguien haya desreferenciado a null. Cuando vea IAE, asume que la persona que llama del método en la parte superior de la pila pasó un valor ilegal. Nuevamente, 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 para un comportamiento diferente: ¿realmente espera que el código de llamada capture los NPE por separado del IAE y, como resultado, haga algo diferente? ¿Estás intentando comunicar un mensaje de error más específico? Pero puede hacerlo en el texto del mensaje de excepción de todos modos, como debería hacerlo para 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 consistentes? ¿Por qué es que un ilegal nulles tan especial que merece una excepción separada de todos los otros 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 los tipos de excepción hasta las convenciones de nomenclatura, por lo que creo que copiar ciegamente (su parte favorita de) la API de Java no es un argumento lo suficientemente bueno como para superar estas otras consideraciones.

Jason Cohen
fuente
120
Efectivo Java 2nd Edition, Elemento 60: "Posiblemente, todas las invocaciones de métodos erróneos se reducen a un argumento ilegal o un estado ilegal, pero otras excepciones se usan de manera estándar para ciertos tipos de argumentos y estados ilegales. Si una persona que llama pasa un valor nulo en algún parámetro para el cual los valores nulos están prohibidos, la convención dicta que se arroje NullPointerException en lugar de IllegalArgumentException. Del mismo modo, si una persona que llama pasa un valor fuera de rango en un parámetro que representa un índice en una secuencia, IndexOutOfBoundsException debe arrojarse en lugar de IllegalArgumentException ".
Gili
33
JavaDoc para NPE también establece lo siguiente: "Las aplicaciones deberían lanzar instancias de esta clase para indicar otros usos ilegales del objeto nulo". Este podría ser más claro :(
R. Martinho Fernandes
12
Desafortunadamente, los métodos de validación Validate.notNull(commons lang) y Preconditions.checkNotNull(guava) arrojan NPE :-(
Aaron Digulla
2
Aunque Guava también tiene Preconditions.checkArgument () arroja IllegalArgumentException ...
michaelok
16
@AaronDigulla, de los documentos de Guava: "Nos damos cuenta de que hay muchos argumentos válidos a favor de lanzar IAE en un argumento nulo. De hecho, si tuviéramos una máquina del tiempo para retroceder> 15 años, incluso podríamos tratar de empujar las cosas esa dirección. Sin embargo, hemos decidido seguir con el JDK y la preferencia efectiva de Java de NullPointerException. Si usted es firme en su creencia de que IAE está en lo cierto, todavía tiene checkArgument(arg != null), sin la conveniencia de que devuelva arg, o puede crear una utilidad local para su proyecto ". code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Arto Bendiken
162

El estándar es lanzar el NullPointerException. El "Java efectivo" generalmente infalible analiza esto brevemente en el Ítem 42 (primera edición), el Ítem 60 (segunda edición) o el Ítem 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 usan de manera estándar para ciertos tipos de argumentos y estados ilegales. Si una persona que llama pasa un valor nulo en algún parámetro para el cual los valores nulos están prohibidos, la convención dicta que Se lanzará NullPointerException en lugar de IllegalArgumentException ".

GaryF
fuente
95
Estoy totalmente en desacuerdo. NullPointerExceptions solo se debe generar si la JVM sigue de manera accidental una referencia nula. Esa es la diferencia que te ayuda cuando te llaman para ver el código a las 3 de la mañana.
Thorbjørn Ravn Andersen
26
No estoy necesariamente de acuerdo con el estándar (en realidad podría ir en cualquier dirección sobre el tema), pero ESO es el uso estándar en todo el JDK, por lo tanto, Java efectivo lo justifica. Creo que este es un caso de elegir si se sigue o no el estándar, o si se hace lo que se siente correcto. A menos que tenga una muy buena razón (y esto ciertamente puede calificar), es mejor seguir la práctica estándar.
GaryF
21
El seguimiento de la excepción muestra el punto de la excepción, por lo que si la diferencia en el tipo de excepción te causa un infierno o es "la diferencia que te ayuda", estás haciendo algo muy malo.
Jim Balter
8
Fantasías y sofismas. Justo debajo, MB escribe "Tenga en cuenta que los argumentos sobre la depuración dura son falsos porque, por supuesto, puede proporcionar un mensaje a NullPointerException diciendo qué fue nulo y por qué no debería ser nulo. Al igual que con IllegalArgumentException".
Jim Balter
10
Como el respondedor original aquí, déjenme decir que simplemente no importa mucho. Ciertamente no garantiza 6 años de conversación. Elija uno, lo que quiera, y sea consistente. El estándar, como señalé, es NPE. Si prefiere IAE por alguna razón, hágalo. Solo sé consistente.
GaryF
138

Estaba totalmente a favor de lanzar IllegalArgumentExceptionparámetros nulos, hasta hoy, cuando noté el java.util.Objects.requireNonNullmétodo en Java 7. Con ese método, en lugar de hacerlo:

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

tu puedes hacer:

Objects.requireNonNull(param);

y arrojará un NullPointerExceptionsi el parámetro que pasa es null.

Dado que ese método es justo en el medio, considero java.utilque su existencia es una indicación bastante fuerte de que lanzar NullPointerExceptiones "la forma Java de hacer las cosas".

Creo que estoy decidido de todos modos.

Tenga en cuenta que los argumentos sobre la depuración dura son falsos porque, por supuesto, puede proporcionar un mensaje para NullPointerExceptiondecir qué fue nulo y por qué no debería ser nulo. Al igual que con IllegalArgumentException.

Una ventaja adicional de esto NullPointerExceptiones que, en un código crítico de alto rendimiento, puede prescindir de una comprobación explícita de nulo (y un NullPointerExceptionmensaje de error amigable), y solo confiar en NullPointerExceptionque obtendrá automáticamente cuando llame a un método en nulo parámetro. Siempre que llame a un método rápidamente (es decir, falle rápidamente), tendrá esencialmente el mismo efecto, pero no 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 cambiar eso si el rendimiento lo dicta sin romper el contrato publicado del método / constructor.

MEGABYTE.
fuente
14
La guayaba Preconditions.checkNotNull(arg)también arroja NPE.
assylias
14
Esto realmente no está agregando más peso a NullPointerException para ARGUMENTOS nulos ilegales. Tanto el JDK requireNonNull () como Guava checkNotNull () se pueden llamar en cualquier parte del código, con cualquier objeto. Podría llamarlos dentro de un bucle, por ejemplo. requireNotNull () y checkNotNull () no podrían suponerse invocados con algunos argumentos de método y lanzar IllegalArgumentException. Tenga en cuenta que Guava también tiene Preconditions.checkArgument () que arroja IllegalArgumentException.
Bogdan Calmac
2
Un punto justo de Bogdan, aunque sospecho que el uso típico (y generalmente previsto) de requireNonNull es para la verificación de argumentos. Si necesitara comprobar que algo no era nulo en un bucle, hubiera pensado que una aserción sería la forma típica.
MB.
15
Creo que el JavaDoc de Object.requireNonNull () agrega peso al argumento: "Este método está diseñado principalmente para realizar la validación de parámetros en métodos y constructores"
Richard Zschech
Tenga en cuenta que el argumento de rendimiento a favor de las comprobaciones nulas implícitas a menudo no es válido. El JIT puede reconocer las comprobaciones nulas del usuario y eludir la siguiente comprobación nula implícita, y / o utilizar el mismo conjunto de optimizaciones en cualquier tipo de comprobación nula. Consulte esta wiki para obtener más información, en particular: las comprobaciones nulas escritas por el usuario son en la mayoría de los casos funcionalmente idénticas a las insertadas por la JVM. Por supuesto, si está haciendo algo más elegante en su nulo como mensajes personalizados, esta optimización puede no aplicarse.
BeeOnRope
70

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.containsKeyestados:

@throws NullPointerException si la clave es nula y este mapa no permite claves nulas (opcional).

Es perfectamente válido lanzar tu propio 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 lanza una excepción más tarde cuando otro código intente usarlo. Eso hace que la depuración sea una pesadilla. Siempre debe seguir el principio de "falla rápida".

Mark Renouf
fuente
3
Alimento para pensar: Tal vez la razón por la que NullPointerException no extiende IllegalArgumentException es que lo primero puede ocurrir en casos que no involucran argumentos de método.
Gili
2
@Gili: quizás este problema exista en primer lugar porque Java no admite la herencia múltiple. Si Java admite MI, podrá lanzar una excepción que herede tanto de IllegalArgumentException como de NullPointerException.
Lie Ryan
77
El mensaje no necesita incluir el argumento, ya que siempre sería nulo, dando: "nulo no debe ser nulo", no muy útil. :-) De lo contrario, estoy de acuerdo, puede hacer un NPE "rico", con un mensaje significativo.
PhiLho
55
Tengo que estar de acuerdo: siga la API estándar cuando tenga dudas. No todo en la API es óptimo, pero aún así es mantenido e iterado por cientos de desarrolladores y utilizado por millones de programadores. Ahora en Java 7 tenemos otro ejemplo del uso de NPE de esta manera; El método Objects.requireNonNull (T obj): se especifica claramente para verificar que las referencias de objeto no son nulas, se especifica claramente para realizar la validación de parámetros en métodos / constructores y se especifica claramente para lanzar un NPE si el objeto es nulo. Fin de
flamming_python
44

Votó el 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 solo se limitara a situaciones en las que el tiempo de ejecución encuentra un valor nulo cuando no debería, todos estos casos podrían definirse de manera mucho más sucinta.

  • No puede evitarlo si asume lo incorrecto, pero suponiendo que la encapsulación se aplique correctamente, realmente no debería importarle o notar si un nulo fue desreferenciado de manera inapropiada frente a si un método detectó un nulo inapropiado y activó una excepción.

  • Elegiría NPE sobre IAE por múltiples razones

    • Es más específico sobre la naturaleza de la operación ilegal.
    • La lógica que permite 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 es con el usuario final de la aplicación. Si obtengo un valor nulo, es un error del programador.
    • Los valores no válidos pueden causar desbordamientos de la 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 de método. Por esta razón, veo a IAE como la MÁS GENERAL de todas las excepciones bajo RuntimeException.
  • En realidad, otros argumentos inválidos pueden dar lugar a todo tipo de otras excepciones. UnknownHostException , FileNotFoundException , una variedad de excepciones de error de sintaxis, IndexOutOfBoundsException , fallas de autenticación, etc., etc.

En general, siento que NPE está muy difamado porque tradicionalmente se ha asociado con código que no sigue el principio de falla rápida . Eso, más el hecho de que el JDK no haya llenado los NPE con una cadena de mensajes realmente ha creado un fuerte sentimiento negativo que no está bien fundado. 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 sea con el nombre, más claridad le dará a la persona que llama.

Christopher Smith
fuente
La diferencia entre la mayoría de las excepciones no marcadas es solo el nombre.
Thorbjørn Ravn Andersen
20

Es una pregunta de estilo de "Guerra Santa". En otras palabras, ambas alternativas son buenas, pero las personas tendrán sus preferencias que defenderán hasta la muerte.

Steve McLeod
fuente
No, solo hay una respuesta correcta a esta pregunta y es usar la excepción throw IllegalArgument cuando la entrada al método es incorrecta. También en el entorno de desarrollo, puede usar aserciones para verificar la validez de entrada y lanzar la excepción adecuada;)
Mr.Q
@ Mr.Q Y creo que NullPointerExceptiondebería lanzarse: es la convención que utiliza el JDK, y requiere para las interfaces, es más específica (como IndexOutOfBoundsException, etc.), etc.
Solomon Ucko
kekekekkek ...: D
Yousha Aleayoub
17

Si es un settermétodo y nullse le está pasando, creo que tendría más sentido lanzar un IllegalArgumentException. A NullPointerExceptionparece tener más sentido en el caso en el que intenta utilizar realmente el null.

Por lo tanto, si usted está usando y que es null, NullPointer. Si es que se pasa en y es null, IllegalArgument.

Jeremy Privett
fuente
9

Apache Commons Lang tiene una NullArgumentException que 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 siento que lanzar algo como NullArgumentException o IllegalArgumentException describe con mayor precisión las circunstancias excepcionales, mis colegas y yo hemos optado por diferir los consejos de Bloch sobre el tema.

Brian T. Grant
fuente
77
Tenga en cuenta que lo eliminaron de commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol
7

No podría estar más de acuerdo con lo que se dice. Falla temprano, falla rápido. Bastante bueno Excepción mantra.

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

Mis 2 centavos

Allain Lalonde
fuente
7

En realidad, la cuestión de lanzar IllegalArgumentException o NullPointerException es, en mi humilde opinión, solo 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 argumento deben indicarse lo más rápido posible (-> falla rápida), para evitar estados ilegales que son mucho más difíciles de depurar
  • en caso de un puntero nulo inválido por cualquier razón, arroje NullPointerException
  • en caso de un índice ilegal de matriz / colección, arroje ArrayIndexOutOfBounds
  • en caso de un tamaño negativo de matriz / colección, arroje NegativeArraySizeException
  • en caso de un argumento ilegal que no esté cubierto por lo anterior, y para el que no tenga otro tipo de excepción más específico, arroje IllegalArgumentException como una papelera
  • por otro lado, en caso de una violación de restricción DENTRO DE UN CAMPO que no podría evitarse por una falla rápida por alguna razón válida, atrapar y volver a lanzar como IllegalStateException o una excepción comprobada más específica. ¡Nunca deje pasar el NullPointerException original, ArrayIndexOutOfBounds, etc. en este caso!

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

(1) Un programador no puede suponer con seguridad que todos los casos de violaciones de restricciones de argumentos dan como resultado IllegalArgumentException, porque la gran mayoría de las clases estándar usan esta excepción en lugar de una papelera si no hay más tipos específicos de excepciones disponibles. Intentar asignar todos los casos de violaciones de restricciones de argumentos a IllegalArgumentException en su API solo conduce a la frustración del programador al usar sus clases, ya que las bibliotecas estándar en su mayoría siguen diferentes reglas que violan las suyas, ¡y la mayoría de los usuarios de su API también las usarán!

(2) El mapeo de las 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 realmente sea una NullPointerException y una IllegalArgumentException, ya que las subclases solo pueden heredar de una u otra. Lanzar una excepción IllegalArgumentException en caso de un argumento nulo, por lo tanto, 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, introduciendo valores predeterminados en una repetición de llamada.

(3) El mapeo en realidad crea el peligro de enmascarar errores: para mapear las violaciones de restricciones de argumentos en IllegalArgumentException, deberá codificar un try-catch externo dentro de cada método que tenga argumentos restringidos. Sin embargo, simplemente atrapar RuntimeException en este bloque de captura está fuera de discusión, porque eso corre el riesgo de mapear RuntimeExceptions documentadas generadas por los métodos de libery utilizados dentro de los suyos en IllegalArgumentException, incluso si no son causados ​​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 asigne accidentalmente una excepción de tiempo de ejecución no documentada de otra API (es decir, un error) en una IllegalArgumentException de su API.

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 el llamador de métodos, las reglas también son fáciles: - si encuentra una excepción de tiempo de ejecución documentada de cualquier tipo porque pasó un valor ilegal, repita la llamada con un valor predeterminado (para estas excepciones específicas son necesarias) o corrija su código - por otro lado, si encuentra una excepción de tiempo de ejecución que no está documentada para un conjunto dado de argumentos, presente un informe de error a los creadores del método para asegurarse de que se corrija su código o su documentación.

Sascha Baumeister
fuente
6

La práctica aceptada es usar IllegalArgumentException (mensaje de cadena) para declarar que un parámetro no es válido y dar la mayor cantidad de detalles posible ... Por lo tanto, para decir que se encontró que un parámetro era nulo, mientras que la excepción no era nula, haría algo Me gusta esto:

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

Prácticamente no tiene ninguna razón para usar 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 (Like toString () ).

Claude Houle
fuente
6

Lanzar una excepción que sea exclusiva de los nullargumentos (ya NullPointerExceptionsea ​​un tipo personalizado) hace que las nullpruebas automatizadas sean más confiables. Esta prueba automatizada se puede hacer con reflexión y un conjunto de valores predeterminados, como en Guava 's NullPointerTester. Por ejemplo, NullPointerTesterintentarí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: "", nully null, ImmutableList.of(). Probaría que cada una de estas llamadas arroja lo esperado NullPointerException. Para esta implementación, pasar una nulllista no produce NullPointerException. Sin embargo, sucede que produce un IllegalArgumentExceptionporque NullPointerTesterusa una cadena predeterminada de "". Si NullPointerTesterespera sólo NullPointerExceptionpara nulllos valores, que atrapa el fallo. Si espera IllegalArgumentException, lo echa de menos.

Chris Povirk
fuente
5

Algunas colecciones suponen que nullse rechaza utilizando en NullPointerExceptionlugar de IllegalArgumentException. Por ejemplo, si compara un conjunto que contiene nullun conjunto que rechaza null, el primer conjunto llamará containsAllal otro y capturará su NullPointerException- pero no IllegalArgumentException. (Estoy mirando la implementación de AbstractSet.equals).

Podría argumentar razonablemente que el uso de excepciones no verificadas de esta manera es un antipatrón, que comparar colecciones que contienen nullcon colecciones que no pueden contener nulles un error probable que realmente debería producir una excepción, o que poner nulluna colección es una mala idea . Sin embargo, a menos que esté dispuesto a decir que equalsdebería arrojar una excepción en tal caso, está atrapado recordando que NullPointerExceptionse requiere en ciertas circunstancias, pero no en otras. ("IAE antes de NPE excepto después de 'c' ...")

Chris Povirk
fuente
No veo cómo contiene contiene un NPE dependiendo de un elemento dentro de la colección. La única razón por la que se arroja un NPE (afaict) es si la colección en sí es nula (en cuyo caso se arroja el NPE porque intenta acceder a su iterador). Sin embargo, esto plantea la pregunta de si se debe verificar la entrada nula o si debe propagarse hasta que se intente acceder.
Alowaniak
2
new TreeSet<>().containsAll(Arrays.asList((Object) null));tira NPEporque Listcontiene null.
Chris Povirk
1
Ah, de hecho, TreeSet # contiene throws NPE "si el elemento especificado es nulo y este conjunto utiliza un orden natural, o su comparador no permite elementos nulos". Solo miré AbstractSet que permite nulo, mi mal. Personalmente, me parece extraño que no solo devuelva falso, ya que en ese caso no puede agregarse un valor nulo.
Alowaniak
5

Como pregunta subjetiva, esto debería estar cerrado, pero como todavía está abierto:

Esto es parte de la política interna utilizada en mi lugar de empleo anterior y funcionó muy bien. Todo esto es de memoria, así que no puedo recordar la redacción exacta. Vale la pena señalar que no utilizaron excepciones marcadas, pero eso está más allá del alcance de la pregunta. Las excepciones no comprobadas que usaron se clasificaron en 3 categorías principales.

NullPointerException: no lance intencionalmente. Los NPE solo deben ser lanzados por la VM cuando se desreferencia 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.

IllegalArgumentException: se produce cuando un argumento de una función no se ajusta a la documentación pública, de modo que el error puede identificarse y describirse en términos de los argumentos transmitidos. La situación del OP entraría en esta categoría.

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

Por ejemplo, había dos versiones internas de IndexOutOfBoundsException usadas en cosas que tenían una longitud. Uno es una subclase de IllegalStateException, utilizada si el índice era mayor que la longitud. La otra, una subclase de IllegalArgumentException, utilizada si el índice era negativo. Esto se debía a que podía 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 realmente bien, y le tomó a alguien explicar por qué la distinción existe: "Dependiendo del tipo de error, es bastante sencillo para usted averiguar qué hacer. Incluso si no puede realmente imaginar para averiguar qué salió mal, puede averiguar dónde detectar ese error y crear información de depuración adicional ".

NullPointerException: maneje el caso nulo o ponga una aserción para que no se arroje el NPE. Si pones una afirmación es solo uno de los otros dos tipos. Si es posible, continúe la depuración como si la aserción estuviera allí en primer lugar.

IllegalArgumentException: tienes algo mal en tu sitio de llamadas. Si los valores que se pasan son de otra función, averigüe por qué recibe un valor incorrecto. Si está pasando uno de sus argumentos, el error verifica la pila de llamadas hasta que encuentre la función que no devuelve lo que esperaba.

IllegalStateException: no ha llamado a sus funciones en el orden correcto. Si está utilizando uno de sus argumentos, verifíquelos y arroje una IllegalArgumentException que describa el problema. Luego puede propagar las mejillas contra la pila hasta que encuentre el problema.

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

Ben Seidel
fuente
4

En general, un desarrollador nunca debe lanzar una 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 nulo, en lugar de que solo un valor nulo genere una NullPointerException, debe lanzar una IllegalArgumentException.


fuente
99
JavaDoc en NPE tiene otra opinión: "Las aplicaciones deberían lanzar instancias de esta clase para indicar otros usos ilegales del objeto nulo". No seas tan categórico
Donz
4

Quería destacar los argumentos nulos de otros argumentos ilegales, por lo que obtuve una excepción de IAE llamada NullArgumentException. Sin siquiera tener que 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 capturo la NullArgumentException con un controlador IAE, pero en mis registros es donde puedo ver la diferencia rápidamente.

Jason Fritcher
fuente
He adoptado el enfoque "lanzar nueva IllegalArgumentException (" foo == null ")". Tienes que entrar el nombre de la variable de todos modos (para estar seguro de que usted está buscando en el derecho sttatement etc)
Thorbjørn Ravn Andersen
4

la dicotomía ... ¿No se superponen? Solo las partes no superpuestas de un todo pueden hacer una dicotomía. Como yo lo veo:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
Luis Daniel Mesa Velásquez
fuente
1
Esto duplicaría la sobrecarga para la creación de excepciones y realmente no ayudaría, ya que la captura NullPointerExceptionno haría nada. Lo único que podría ayudar es IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, pero no tenemos herencia múltiple.
maaartinus
Creo que las excepciones más específicas deberían estar envueltas por excepciones más generales. NPE es para una expresión, mientras que IAE es para un método. Como los métodos contienen sentencias que contienen expresiones, IAE es más general.
Sgene9
En cuanto a los gastos generales, no tengo idea. Pero dado que las trazas de pila serían básicamente idénticas, excepto que el nombre de la excepción cambió en el medio, creo que no debería haber demasiada sobrecarga para las excepciones dobles. Si a uno le preocupa la sobrecarga, puede usar declaraciones "if" para devolver un valor nulo o -1 en lugar de lanzar una excepción.
Sgene9
4

NullPointerExceptionarrojado al intentar acceder a un objeto con una variable de referencia cuyo valor actual es null.

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

Nitesh Soomani
fuente
3

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

León
fuente
0

Idealmente, no se deben lanzar excepciones de tiempo de ejecución. Se debe crear una excepción marcada (excepción comercial) para su escenario. Porque si alguna de estas excepciones se inicia y registra, desvía al desarrollador mientras revisa los registros. En cambio, las excepciones comerciales no crean ese pánico y generalmente se ignoran al resolver problemas en los registros.

vijay
fuente
-1

Las definiciones de los enlaces a las dos excepciones anteriores son IllegalArgumentException: se arroja para indicar que un método ha pasado un argumento ilegal o inapropiado. NullPointerException: se produce cuando una aplicación intenta usar nulo en un caso donde se requiere un objeto.

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

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

martinatime
fuente
1
Lo más destacado es que es la aplicación la que está usando nulo, no el tiempo de ejecución. Por lo tanto, existe una superposición bastante grande entre "cuando un método ha pasado un argumento ilegal o inapropiado" y "cuando una aplicación está usando nulo". En teoría, si una aplicación pasa un valor nulo para un campo que requiere un valor no nulo, se cumplen ambos criterios.
Christopher Smith
-1

Si se trata de un "setter", o en algún lugar que voy a obtener un miembro para usar más tarde, 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 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 hacerlo, pero eso es una queja para otro día).

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

erickson
fuente
-1

Debería lanzar una IllegalArgumentException, ya que le resultará obvio al programador que ha hecho algo no válido. Los desarrolladores están tan acostumbrados a ver NPE lanzada por la VM, que cualquier programador no se daría cuenta de inmediato de su error y comenzaría a mirar al azar, o peor aún, culparía a su código de 'buggy'.

Will Sargent
fuente
44
Lo sentimos, si un programador mira a su alrededor "al azar" al obtener cualquier tipo de excepción ... cambiar el nombre de una excepción no va a ayudar mucho.
Christopher Smith
-1

En este caso, IllegalArgumentException transmite información clara al usuario que usa su API 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 usa su API.

GaryF y tweakt descartaron las referencias de "Java efectivo" (que juro) que recomiendan usar 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, "El constructor no debe ser nulo"). El método org.springframework.util.Assert.notNull (objeto de objeto, mensaje de cadena) verifica si el argumento (objeto) pasado es nulo y si lo es, arroja una nueva IllegalArgumentException (mensaje) que luego queda atrapada en la organización. springframework.beans.BeanUtils.instantiateClass (...) método.


fuente
-5

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

jassuncao
fuente
El tiempo de ejecución no incluirá un mensaje significativo.
mP.
En realidad, este comentario podría derivar alguna otra opinión. Deje que la VM hable NPEy los programadores hablen IAEantes de la VM si así lo desean.
Jin Kwon
1
¿Costoso? No creo que == nulo sea tan costoso ... Además, el argumento nulo puede almacenarse para su uso posterior, y arrojará una excepción mucho después de la llamada al método, haciendo que el error sea más difícil de rastrear. O puede crear un objeto costoso antes de usar el argumento nulo, y así sucesivamente. La detección temprana parece ser una buena opción.
PhiLho
La votación negativa de esta respuesta es un malentendido del hardware detrás. Ciertamente, las comprobaciones de hardware (que hace la CPU) son más baratas que las comprobaciones explícitas. La anulación de referencia de nulo es un caso especial de SegmentationFault (SegV) (acceso a una página que no es propiedad del proceso) que CPU / OS verifica y JRE maneja como un caso especial que arroja NullPointerException.
digital_infinity