Estoy creando una API, una función que carga un archivo. Esta función no devolverá nada / nulo si el archivo se cargó correctamente y genera una excepción cuando hay algún problema.
¿Por qué una excepción y no solo falsa? Porque dentro de una excepción puedo especificar la razón del fallo (falta de conexión, nombre de archivo faltante, contraseña incorrecta, descripción de archivo faltante, etc.). Quería crear una excepción personalizada (con algo de enumeración para ayudar al usuario de la API a manejar todos los errores).
¿Es una buena práctica o es mejor devolver un objeto (con un booleano dentro, un mensaje de error opcional y la enumeración para errores)?
java
api-design
exceptions
functions
architectural-patterns
Accollativo
fuente
fuente
Result<T, E>
dóndeT
está el resultado si tiene éxito yE
es el error si no tiene éxito. Lanzar una excepción (puede ser, no tan seguro en Java) puede ser costoso ya que implica desenrollar la pila de llamadas, pero crear un objeto Exception es barato. Obviamente, respete los patrones establecidos del lenguaje que está utilizando, pero no combine booleanos y excepciones como esta.fillInStackTrace();
se llama en el súper constructor, en la claseThrowable
Respuestas:
Lanzar una excepción es simplemente una forma adicional de hacer que un método devuelva un valor. La persona que llama puede verificar un valor de retorno tan fácilmente como detectar una excepción y verificar eso. Por lo tanto, decidir entre
throw
yreturn
requiere otros criterios.Lanzar excepciones a menudo debe evitarse si pone en peligro la eficiencia de su programa (construir un objeto de excepción y desenrollar la pila de llamadas es mucho más trabajo para la computadora que simplemente poner un valor en él). Pero si el propósito de su método es cargar un archivo, entonces el cuello de botella siempre será la red y la E / S del sistema de archivos, por lo que no tiene sentido optimizar el método de retorno.
También es una mala idea lanzar excepciones para lo que debería ser un flujo de control simple (por ejemplo, cuando una búsqueda tiene éxito al encontrar su valor), porque eso viola las expectativas de los usuarios de API. Pero un método que no cumple su propósito es un caso excepcional (o al menos debería serlo), así que no veo ninguna razón para no lanzar una excepción. Y si hace eso, es mejor que lo convierta en una excepción personalizada y más informativa (pero es una buena idea convertirlo en una subclase de una excepción estándar, más general, como
IOException
).fuente
No hay absolutamente ninguna razón para regresar
true
al éxito si no regresafalse
al fracaso. ¿Cómo debería ser el código del cliente?En este caso, la persona que llama necesita un bloque try-catch de todos modos, pero luego puede escribir mejor:
Por lo tanto, el
true
valor de retorno es completamente irrelevante para la persona que llama. Así que solo mantén el métodovoid
.En general, hay tres formas de diseñar modos fallidos.
void
Excepción de , lanzamiento (marcado)Volver
true
/false
Esto se usa en algunas API antiguas, en su mayoría de estilo c. Los inconvenientes son obviuos, no tienes idea de lo que salió mal. PHP hace esto con bastante frecuencia, lo que lleva a un código como este:
En contextos multiproceso, esto es aún peor.
Lanzar excepciones (marcadas)
Esta es una buena manera de hacerlo. En algunos puntos, puede esperar el fracaso. Java hace esto con sockets. La suposición básica es que una llamada debe tener éxito, pero todos saben que ciertas operaciones pueden fallar. Las conexiones de socket están entre ellas. Entonces la persona que llama se ve obligada a manejar la falla. es un diseño agradable, porque se asegura de que la persona que llama realmente maneje la falla y le brinda a la persona que llama una forma elegante de lidiar con la falla.
Objeto de resultado devuelto
Esta es otra buena manera de manejar esto. A menudo se usa para analizar o simplemente cosas que deben validarse.
Niza, lógica limpia para la persona que llama también.
Hay un poco de debate sobre cuándo usar el segundo caso y cuándo usar el tercero. Algunas personas creen que las excepciones deben ser excepcionales y que no debe diseñar teniendo en cuenta la posibilidad de excepciones, y casi siempre utilizará las terceras opciones. Así de fino. Pero hemos verificado las excepciones en Java, por lo que no veo ninguna razón para no usarlas. Utilizo las comprobaciones comprobadas cuando la suposición básica es que la llamada debería éxito (como usar un socket), pero es posible que falle, y uso la tercera opción cuando no está claro si la llamada debe tener éxito (como validar los datos). Pero hay diferentes opiniones sobre esto.
En tu caso, iría con
void
+Exception
. Espera que la carga del archivo tenga éxito, y cuando no lo hace, es excepcional. Pero la persona que llama se ve obligada a manejar ese modo de falla, y puede devolver una excepción que describa correctamente qué tipo de error ocurrió.fuente
Esto realmente se reduce a si una falla es excepcional o esperada .
Si un error no es algo que generalmente espera, entonces es razonablemente probable que el usuario de la API simplemente llame a su método sin ningún manejo especial de errores. Lanzar una excepción permite que burbujee la pila a un lugar donde se note.
Si, por otro lado, los errores son comunes, debe optimizar para el desarrollador que los está comprobando, y las
try-catch
cláusulas son un poco más engorrosas que unaif/elif
oswitch
serie.Diseñe siempre una API en la mentalidad de alguien que la esté utilizando.
fuente
No devuelva un booleano si nunca tiene la intención de regresar
false
. Simplemente haga el métodovoid
y documente que arrojará una excepción (IOException
es adecuada) en caso de falla.La razón de esto es que si devuelve un valor booleano, el usuario de su API puede concluir que él / ella puede hacer esto:
Eso no funcionará, por supuesto; es decir, existe una incongruencia entre el contrato de su método y su comportamiento. Si arroja una excepción marcada, el usuario del método debe manejar la falla:
fuente
Si su método tiene un valor de retorno, lanzar una excepción podría sorprender a sus usuarios. Si veo que un método devuelve un valor booleano, estoy bastante convencido de que devolverá verdadero si tiene éxito y falso si no lo hace, y estructuraré mi código usando una cláusula if-else. Si su excepción se basará en una enumeración de todos modos, también puede devolver un valor de enumeración, similar a Windows HResults, y mantener un valor de enumeración para cuando el método tenga éxito.
También es molesto tener una excepción de lanzamiento de método cuando no es el paso final de un procedimiento. Tener que escribir un try-catch y desviar el flujo de control al bloque catch es una buena receta para los espaguetis y debe evitarse.
Si avanza con excepciones, intente devolver void en su lugar, los usuarios descubrirán que tiene éxito si no se lanzan excepciones, y ninguno intentará usar una cláusula if-else para desviar el flujo de control.
fuente