Pregunta

Después de publicar esta pregunta y leyendo Aquél Me di cuenta de que es muy importante saber si se supone que un método debe devolver un valor nulo o si esto se considera una condición de error y se deben generar excepciones.También hay una buena discusión sobre cuándo devolver 'nulo' o lanzar una excepción .

Estoy escribiendo un método y ya sé si quiero devolver null o lanzar una excepción, ¿cuál es la mejor manera de expresar mi decisión, en otras palabras, documentar mi contrato?

Algunas formas en las que puedo pensar:

  • Anótelo en las especificaciones/documentación (¿alguien lo leerá?)
  • Hágalo parte del nombre del método (como sugerí aquí)
  • asumir que cada método que lanza una excepción será no devuelve nulo, y cada uno que 'no' arroja podría devolver nulo.

Me refiero principalmente a Java, pero podría aplicarse también a otros lenguajes:¿Por qué existe una forma formal de expresar si se lanzarán excepciones (el throws palabras clave) pero no hay una forma formal de expresar si se puede devolver un valor nulo?

¿Por qué no hay algo así?

public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

Resumen y conclusión

Hay muchas formas de expresar el contrato:

  • Si su IDE lo admite (como IntelliJ), es mejor usar una anotación como @NotNull porque es visible para el programador y puede usarse para la verificación automática del tiempo de compilación.Hay una complemento para eclipse para agregar soporte para estos, pero no funcionó para mí.
  • Si estas no son una opción, use tipos personalizados como Option<T> o NotNull<T>, que añaden claridad y al menos comprobación del tiempo de ejecución.
  • De cualquier manera, documentar el contrato en el JavaDoc nunca está de más y, a veces, incluso ayuda.
  • Usar nombres de métodos para documentar el anulabilidad La estimación del valor de retorno no fue propuesta por nadie más que por mí, y aunque puede ser muy detallado y no siempre útil, sigo creyendo que a veces también tiene sus ventajas.
¿Fue útil?

Solución

Una muy buena pregunta de seguimiento.Yo considero null un valor verdaderamente especial, y si un método puede devolver null debe documentar claramente en el Javadoc cuando lo haga (@return some value ..., or null if ...).Al codificar estoy a la defensiva y asumo que un método puede regresar null a menos que esté convencido de que no puede (por ejemplo, porque el Javadoc lo dice).

La gente se dio cuenta de que esto es un problema y una solución propuesta es utilizar anotaciones para expresar la intención de manera que pueda verificarse automáticamente.Ver JSR 305:Anotaciones para la detección de defectos de software, JSR 308:Anotaciones sobre tipos de Java y Procedimiento anulable de JetBrain.

Su ejemplo podría verse así y ser rechazado por el IDE, el compilador u otras herramientas de análisis de código.

@NotNull
public Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

Otros consejos

Puedes usar el Option tipo, que es muy parecido a una lista que tiene cero o un elemento.Un tipo de retorno de Option<Object> indica que el método puede devolver un Object, o puede devolver un valor especial de tipo None.Este tipo reemplaza el uso de null con mejores comprobaciones de tipo.

Ejemplo:

public Option<Integer> parseInt(String s) {
   try {
      return Option.some(Integer.parseInt(s));
   }
   catch (Exception e) {
      return Option.none();
   }
}

Si usa esto de manera constante, puede activar las advertencias nulas del IDE o simplemente usar grep para null que no debería aparecer en tu código en absoluto si usas Option.none() en todos los lugares donde normalmente usarías un null literal.

Option Viene de serie con Scala y se llama Maybe en Haskel.El enlace de arriba es a una biblioteca llamada Java funcional eso lo incluye.Esa versión implementa la Iterable interfaz y tiene métodos monádicos que te permiten componer cosas muy bien.Por ejemplo, para proporcionar un valor predeterminado de 0 en caso de None:

int x = optionalInt.orSome(0);

Y puedes reemplazar esto...

if (myString != null && !"".equals(myString))

...con esto, si tienes un Option<String>...

for (String s : myOptionString)

De hecho: en nuestro marco tenemos un tipo de puntero 'no nulo', que puede devolverse para indicar que el método siempre devolverá un valor.

Veo tres opciones:

  1. espere a que el soporte de idiomas lo exprese (por ejemplo, el C #?! cosa)
  2. use la Orientación de aspecto para crear sus propias extensiones de idioma para expresarlo
  3. usa un tipo personalizado para expresarlo
  4. (pero se basa en la cooperación del desarrollador) utiliza un esquema de nombres para indicarlo

Para Java, se puede usar la descripción Javadoc de un método para documentar el significado del valor devuelto, incluido si puede ser nulo. Como se ha mencionado, las anotaciones también pueden proporcionar asistencia aquí.

Por otro lado, admito que no veo nulo como algo a lo que temer. Hay situaciones en las que & Quot; nadie está en casa & Quot; es una condición significativa (aunque la técnica de objeto nulo también tiene un valor real aquí).

Es cierto que intentar una invocación de método en un valor nulo causará una excepción. Pero también lo intentará dividir por cero. ¡Eso no significa que debamos ir a una campaña para eliminar los ceros! Simplemente significa que necesitamos entender el contrato en un método y hacer lo correcto con los valores que devuelve.

¿Ha echado un vistazo a Spec # ?

Puede escribir su propia anotación (Java) o atributo (C #) para indicar que el valor de retorno puede ser nulo. Nada lo comprobará automáticamente (aunque .NET 4.0 tendrá contratos de código para este tipo de cosas), pero al menos actuaría como documentación.

Existe cierta compatibilidad para una @Nullable y @NotNull anotación en IntelliJ IDEA . También se habla de agregar esas anotaciones (o una característica similar) a Java 7. Lamentablemente, no sé qué tan lejos llegó o si todavía está en camino.

Tal vez podría definir una clase genérica llamada " NotNull " ;, para que su método sea así:

public NotNull<Object> methodWhichCannotReturnNull(int i) throws Exception
{
   // the following would lead to a run-time error thown by the
   // NotNull constructor, if it's constructed with a null value
   return new NotNull<Object>(null);
}

Esto sigue siendo una verificación en tiempo de ejecución (no en tiempo de compilación), pero:

  • Se lanza en la implementación del método (no es una falla en el código de llamada)
  • Se documenta por sí mismo (la persona que llama sabe que está obteniendo NotNull<T> como un tipo de retorno)

A toda costa, evite confiar en los JavaDocs. La gente solo los lee si la firma no parece trivial y se explica por sí misma (lo cual es malo para empezar), y aquellos que realmente se molestan en leerlos tienen menos probabilidades de cometer un error con los nulos, ya que actualmente están siendo más cuidadosos .

Si está utilizando Java 5+, puede usar una anotación personalizada, p. @MayReturnNull

UPDATE

Dejando a un lado toda la filosofía de codificación (devolviendo nulo, usando excepciones, afirmaciones, yada yada), espero que lo anterior responda a su pregunta. Además de las primitivas que tienen valores predeterminados, los tipos complejos pueden ser nulos o no, y su código debe tratar con ellos.

En términos generales, asumiría que un valor de retorno nulo está en contra del contrato de la API de forma predeterminada. Casi siempre es posible diseñar su código de modo que nunca se devuelva un valor nulo de sus API durante & Quot; normal & Quot; flujo de ejecución. (Por ejemplo, marque foo.contains (obj) en lugar de llamar a foo.get (obj) y tener una rama separada para null. O, use Patrón de objeto nulo .

Si no puede diseñar su API de esa manera, documentaría claramente cuándo y por qué podría arrojarse un valor nulo, como mínimo en el Javadoc, y posiblemente también utilizando una anotación personalizada como como han sugerido varias de las otras respuestas.

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