Pregunta

Tengo un código que proporciona una identificación de usuario a una utilidad que luego envía un correo electrónico a ese usuario.

emailUtil.sendEmail(userId, "foo");

public void sendEmail(String userId, String message) throws MailException {
    /* ... logic that could throw a MailException */
}

MailException podría lanzarse por varias razones, problemas con la dirección de correo electrónico, problemas con la plantilla de correo, etc.

Mi pregunta es esta:¿Crea un nuevo tipo de excepción para cada una de estas excepciones y luego las trata individualmente o crea una MailException y luego almacena algo en la excepción (algo legible por computadora, no el texto de descripción) que nos permite hacer cosas diferentes? basado en lo que realmente sucedió.

Editar: Como aclaración, las excepciones no son para registros y demás, esto se relaciona con cómo reacciona el código ante ellos.Para seguir con el ejemplo del correo, digamos que cuando enviamos correo podría fallar porque no tienes una dirección de correo electrónico, o podría hacerlo porque no tienes una válido dirección de correo electrónico, o podría fallar..etc.

Mi código querría reaccionar de manera diferente a cada uno de estos problemas (principalmente cambiando el mensaje devuelto al cliente, pero también la lógica real).

¿Sería mejor tener una implementación de excepción para cada uno de estos problemas o una excepción general que tuviera algo interno (por ejemplo, una enumeración) que permitiera al código distinguir qué tipo de problema era?

¿Fue útil?

Solución

Normalmente comienzo con una excepción general y la subclasifica según sea necesario.Siempre puedo detectar la excepción general (y con ella todas las excepciones subclasificadas) si es necesario, pero también la específica.

Un ejemplo de Java-API es IOException, que tiene subclases como FileNotFoundException o EOFException (y muchas más).

De esta manera obtienes las ventajas de ambos, no tienes cláusulas de lanzamiento como:

throws SpecificException1, SpecificException2, SpecificException3 ...

un general

throws GeneralException

es suficiente.Pero si desea tener una reacción especial ante circunstancias especiales, siempre puede detectar la excepción específica.

Otros consejos

En mi código, encuentro que la MAYORÍA de las excepciones se filtran hasta una capa de UI donde son capturadas por mis controladores de excepciones que simplemente muestran un mensaje al usuario (y escriben en el registro).Después de todo, es una excepción inesperada.

A veces, quiero detectar una excepción específica (como parece que usted quiere hacer).Probablemente encontrará, sin embargo, que esto es algo raro y que es indicativo del uso de excepciones para controlar la lógica, lo cual es ineficiente (lento) y a menudo está mal visto.

Entonces, usando su ejemplo, si desea ejecutar alguna lógica especial cuando el servidor de correo electrónico no está configurado, es posible que desee agregar un método al objeto emailUtil como:

bool público esEmailConfigured()

...Llámelo primero, en lugar de buscar una excepción específica.

Cuando ocurre una excepción, realmente significa que la situación fue completamente inesperada y el código no puede manejarla, por lo que lo mejor que puede hacer es informarlo al usuario (o escribirlo en un registro o reiniciar).

En cuanto a tener una jerarquía de excepciones frente a excepciones con códigos de error, normalmente hago lo último.Es más fácil agregar nuevas excepciones si solo necesita definir una nueva constante de error en lugar de una clase completamente nueva.Pero no importa mucho siempre que intentes ser coherente a lo largo de tu proyecto.

@Chris.animado

Sabes que puedes pasar un mensaje en tu excepción, o incluso los "códigos de estado".Estás reinventando la rueda aquí.

Descubrí que si necesita que el CÓDIGO decida qué hacer en función de la excepción devuelta, cree una subclase de excepción bien nombrada con un tipo base común.El mensaje transmitido debe considerarse "sólo para ojos humanos" y demasiado frágil para tomar decisiones sobre él.¡Deje que el compilador haga el trabajo!

Si necesita pasar esto a una capa superior a través de un mecanismo que no reconoce las excepciones marcadas, puede envolverlo en una subclase con nombre adecuado de RuntimeException (MailDomainException) que puede detectarse en lo alto y actuar sobre la causa original.

Depende de lo que esté haciendo su aplicación.Es posible que desee lanzar excepciones individuales en casos como

  • La aplicación es de alta disponibilidad.
  • Enviar correo electrónico es particularmente importante
  • El alcance de la aplicación es pequeño y el envío de correo electrónico es una gran parte de ella.
  • La aplicación se implementará en un sitio remoto y solo obtendrá registros para la depuración.
  • Puede recuperarse de algún subconjunto de excepciones encapsuladas en mailException pero no de otras.

En la mayoría de los casos, diría que simplemente registre el texto de la excepción y no pierda el tiempo granularizando excepciones que ya son bastante granulares.

Creo que una combinación de lo anterior le dará el mejor resultado.

Puede lanzar diferentes excepciones según el problema.p.ej.Dirección de correo electrónico faltante = ArgumentException.

Pero luego, en la capa de la interfaz de usuario, puede verificar el tipo de excepción y, si es necesario, el mensaje y luego mostrar un mensaje apropiado al usuario.Personalmente tiendo a mostrar solo un mensaje informativo al usuario si se lanza un cierto tipo de excepción (UserException en mi aplicación).Por supuesto, debe limpiar y verificar la entrada del usuario tanto como sea posible más arriba en la pila para asegurarse de que las excepciones se generen en escenarios realmente improbables, no como un filtro para correos electrónicos con formato incorrecto que se pueden verificar fácilmente con una expresión regular.

Tampoco me preocuparía por las implicaciones en el rendimiento de detectar una excepción a partir de la entrada del usuario.La única vez que verá problemas de rendimiento debido a excepciones es cuando se lanzan y quedan atrapadas en un bucle o similar.

En lugar de utilizar excepciones, tiendo a devolver una lista de objetos de estado de métodos que pueden tener problemas de ejecución.Los objetos de estado contienen una enumeración de gravedad (información, advertencia, error, ...), un nombre de objeto de estado como "Dirección de correo electrónico" y un mensaje legible por el usuario como "Dirección de correo electrónico mal formateada".

El código de llamada decidiría entonces cuál filtrar en la interfaz de usuario y cuál manejar por sí mismo.

Personalmente, creo que las excepciones son estrictamente para cuando no se puede implementar una solución de código normal.El impacto en el rendimiento y las restricciones de manejo son demasiado para mí.

Otra razón para utilizar una lista de objetos de estado es que identificar múltiples errores (como durante la validación) es MUCHO más fácil.Después de todo, sólo puedes lanzar una excepción que debe manejarse antes de continuar.

Imagine a un usuario que envía un correo electrónico con una dirección de destino con formato incorrecto y un idioma que usted está bloqueando.¿Lanza la excepción de correo electrónico con formato incorrecto y luego, después de corregirlo y volver a enviarlo, lanza una excepción de lenguaje incorrecto?Desde la perspectiva de la experiencia del usuario, tratar con todos ellos a la vez es una mejor manera de hacerlo.

ACTUALIZAR: combinando respuestas

@Jonathan:Mi punto era que puedo evaluar la acción, en este caso enviando un correo electrónico, y devolver múltiples motivos de falla.Por ejemplo, "dirección de correo electrónico incorrecta", "título del mensaje en blanco", etc.

Con una excepción, está limitado a filtrar un problema y luego pedirle al usuario que vuelva a enviarlo, momento en el que descubre un segundo problema.Este es un diseño de interfaz de usuario realmente malo.

Reinventando la rueda..posiblemente.Sin embargo, la mayoría de las aplicaciones deben analizar toda la transacción para brindar la mejor información posible al usuario.Imagínese si su compilador se detuviera en seco ante el primer error.Luego corrige el error y presiona compilar nuevamente solo para que se detenga nuevamente debido a un error diferente.Qué dolor en el trasero.Para mí, ese es exactamente el problema de lanzar excepciones y de ahí la razón por la que dije que usara un mecanismo diferente.

Tiendo a tener menos tipos de excepciones, aunque en realidad no es la forma OO de hacerlo.En lugar de eso, puse una enumeración para mis excepciones personalizadas, que clasifica la excepción.La mayoría de las veces tengo una excepción base personalizada, que retiene un par de miembros, que pueden anularse o personalizarse en tipos de excepción derivados.

Hace un par de meses yo blogueado sobre la idea de cómo internacionalizar las excepciones.Incluye algunas de las ideas mencionadas anteriormente.

Si bien puede diferenciar la ejecución del código buscando la excepción, no importa si se realiza mediante el "modo de jerarquía de tipo de excepción de captura" o por "if(...) else...modo de código de excepción"

pero si está desarrollando software que va a ser utilizado por otras personas, como una biblioteca, creo que es útil crear sus propios tipos de excepciones para notar a las otras personas que su software puede generar otras excepciones además de las normales, y es mejor que las detecten y resolverlos.

Cuando uso una biblioteca y sus métodos simplemente lanzan una 'Excepción' siempre me pregunto:¿Qué puede causar esta excepción?, ¿cómo debe reaccionar mi programa?, si hay un javadoc tal vez se explique la causa, pero muchas veces no hay javadoc o no se explica la excepción.Se pueden evitar demasiados gastos generales con WellChossenExceptionTypeName

Depende de si el código que detecta la excepción necesita diferenciar entre excepciones o si simplemente está utilizando excepciones para fallar en una página de error.Si necesita diferenciar entre una excepción NullReference y su MailException personalizada más arriba en la pila de llamadas, dedique tiempo a escribirla.Pero la mayoría de las veces los programadores simplemente usan excepciones como un todo para generar un error en la página web.En este caso, simplemente está desperdiciando esfuerzo escribiendo una nueva excepción.

yo simplemente pasaría

throw new exception("WhatCausedIt")

Si desea manejar sus excepciones, puede pasar un código en lugar de "WhatCausedIt" y luego reaccionar a las diferentes respuestas con una declaración de cambio.

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