Pregunta

Soy de un fondo .NET y ahora incursiono en Java.

Actualmente, estoy teniendo grandes problemas para diseñar una API a la defensiva contra entradas defectuosas. Digamos que tengo el siguiente código (lo suficientemente cerca):

public void setTokens(Node node, int newTokens) {
    tokens.put(node, newTokens);
}

Sin embargo, este código puede fallar por dos razones:

  1. El usuario pasa un nodo nulo .
  2. El usuario pasa un nodo no válido, es decir, uno no contenido en el gráfico.

En .NET, lanzaría un ArgumentNullException (en lugar de una NullReferenceException !) O una ArgumentException respectivamente, pasando el nombre del argumento ofensor ( nodo ) como cadena argumento.

Java no parece tener excepciones equivalentes. Me doy cuenta de que podría ser más específico y simplemente lanzar cualquier excepción que esté más cerca de describir la situación, o incluso escribir mi propia clase de excepción para la situación específica.

¿Es esta la mejor práctica? ¿O hay clases de propósito general similares a ArgumentException en .NET?

¿Tiene sentido incluso comparar con null en este caso? El código fallará de todos modos y el seguimiento de la pila de la excepción contendrá la llamada al método anterior. La comprobación de null parece redundante y excesivo. Por supuesto, el seguimiento de la pila será ligeramente más limpio (ya que su objetivo es el método anterior, en lugar de una verificación interna en la implementación HashMap del JRE). Pero esto debe compensarse con el costo de una declaración if adicional, que, además, debería nunca ocurrir de todos modos & # 8211; & nbsp; después de todo, pasar nulo para el método anterior no es una situación esperada, es un error bastante estúpido. Esperar que sea francamente paranoico & # 8211; & nbsp; y fallará con la misma excepción, incluso si no lo compruebo.

[Como se ha señalado en los comentarios, HashMap.put en realidad permite valores null para la clave. Por lo tanto, una verificación contra null no necesariamente sería redundante aquí.]

¿Fue útil?

Solución

Los diferentes grupos tienen diferentes estándares.

En primer lugar, supongo que conoce la diferencia entre RuntimeException s (sin marcar) y la Exception s normal (marcada), si no, entonces vea esta pregunta y las respuestas . Si escribe su propia excepción, puede forzar su captura, mientras que NullPointerException y IllegalArgumentException son RuntimeExceptions que están mal vistas en algunos círculos.

En segundo lugar, como con usted, los grupos con los que he trabajado pero no usan activamente afirmaciones, pero si su equipo (o consumidor de la API) ha decidido que utilizará afirmaciones, entonces afirme que suena como el mecanismo correcto.

Si fuera usted, usaría NullPointerException . La razón de esto es precedente. Tome un ejemplo de API de Java de Sun, por ejemplo java.util.TreeSet . Esto usa NPE para precisamente este tipo de situación, y aunque parece que su código acaba de usar un valor nulo, es completamente apropiado.

Como otros han dicho, IllegalArgumentException es una opción, pero creo que NullPointerException es más comunicativo.

Si esta API está diseñada para ser utilizada por empresas / equipos externos, me quedaría con NullPointerException , pero asegúrese de que esté declarada en el javadoc. Si es para uso interno, entonces puede decidir que vale la pena agregar su propia jerarquía de excepciones, pero personalmente encuentro que las API que agregan enormes jerarquías de excepción, que solo serán printStackTrace () do logueado son solo una pérdida de esfuerzo.

Al final del día, lo principal es que su código se comunica claramente. Una jerarquía de excepción local es como la jerga local: agrega información para los iniciados pero puede confundir a los externos.

En cuanto a la verificación contra nulo, diría que tiene sentido. En primer lugar, le permite agregar un mensaje sobre lo que era nulo (es decir, nodo o tokens) cuando construye la excepción que sería útil. En segundo lugar, en el futuro podría usar una implementación Map que permita null , y luego perdería la verificación de error. El costo es casi nulo, así que a menos que un generador de perfiles diga que es un problema de bucle interno, no me preocuparía.

Otros consejos

La excepción estándar de Java es IllegalArgumentException . Algunos arrojarán NullPointerException si el argumento es nulo, pero para mí, NPE tiene que "alguien lo arruinó". connotación, y no quieres que los clientes de tu API piensen que no sabes lo que estás haciendo.

Para las API públicas, verifique los argumentos y falle antes y de manera limpia. El tiempo / costo apenas importa.

En Java normalmente lanzarías una IllegalArgumentException

Si desea una guía sobre cómo escribir un buen código Java, le recomiendo el libro Java efectivo de Joshua Bloch.

Parece que este podría ser un uso apropiado para un afirmar :

public void setTokens(Node node, int newTokens) {
    assert node != null;
    tokens.put(node, newTokens);
}

Su enfoque depende completamente de qué contrato ofrece su función a las personas que llaman: ¿es una condición previa que el nodo no sea nulo?

Si es así, debe lanzar una excepción si el nodo es nulo, ya que es una violación del contrato. Si no es así, su función debe manejar silenciosamente el nodo nulo y responder adecuadamente.

Creo que mucho depende del contrato del método y de qué tan bien se conoce a la persona que llama.

En algún momento del proceso, la persona que llama podría tomar medidas para validar el nodo antes de llamar a su método. Si conoce a la persona que llama y sabe que estos nodos siempre están validados, entonces creo que está bien suponer que obtendrá buenos datos. Esencialmente la responsabilidad recae en la persona que llama.

Sin embargo, si, por ejemplo, está proporcionando una biblioteca de terceros que se distribuye, debe validar el nodo para nulos, etc. ...

Una ilegalArugementException es el estándar de Java pero también es una RunTimeException. Entonces, si desea obligar a la persona que llama a manejar la excepción, entonces debe proporcionar una excepción de verificación, probablemente una personalizada que cree.

Personalmente, me gustaría que NullPointerExceptions SOLO ocurriera por accidente, por lo que se debe usar algo más para indicar que se pasó un valor de argumento ilegal. IllegalArgumentException está bien para esto.

if (arg1 == null) {
 throw new IllegalArgumentException("arg1 == null");
}

Esto debería ser suficiente para los que leen el código, pero también para la pobre alma que recibe una llamada de soporte a las 3 de la mañana.

(y SIEMPRE proporcione un texto explicativo para sus excepciones, lo agradecerá algún día triste)

como el otro: java.lang.IllegalArgumentException. Sobre la comprobación del nodo nulo, ¿qué pasa con la comprobación de entradas incorrectas en la creación del nodo?

No tengo que complacer a nadie, así que lo que hago ahora como código canónico es

void method(String s) 

if((s != null) && (s instanceof String) && (s.length() > 0x0000))
{

que me duerme mucho.

Otros no estarán de acuerdo.

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