2008-08-22 18 views
9

Tengo un código que da una identificación de usuario a una utilidad que luego envía un correo electrónico a ese usuario.¿Escribes excepciones para problemas específicos o excepciones generales?

emailUtil.sendEmail(userId, "foo"); 

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

MailException, pueden salir proyectados por una serie de razones, los problemas con la dirección de correo electrónico, los problemas con la plantilla de correo, etc.

Mi pregunta es la siguiente: Cómo se crea un nuevo tipo de excepción para cada uno de estas excepciones y luego tratar con ellos individualmente o crear una MailException y luego almacenar algo en la excepción (algo legible por computadora, no el texto de descripción) que nos permite hacer cosas diferentes en función de lo que realmente sucedió.

Editar: Como aclaración, las excepciones no son para los registros y lo que no, esto se relaciona con la forma en que el código reacciona a ellos. Para continuar con el ejemplo del correo, digamos que cuando enviamos el correo puede fallar porque no tiene una dirección de correo electrónico, o podría ser porque no tiene una dirección de correo electrónico válida, o podría fallar. etc.

Mi código querría reaccionar de manera diferente a cada uno de estos problemas (sobre todo al cambiar 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 global que tuviera algo interno (un enum decir) que permitiera al código distinguir qué clase de problema era?

Respuesta

8

Por lo general, comienzo con una excepción general y la subclase 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 la API de Java es IOException, que tiene subclases como FileNotFoundException o EOFException (y mucho más).

esta manera se obtiene las ventajas de ambos, usted no tiene un saque de cláusulas 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.

+0

¿Por qué el voto a favor? ¿Qué está mal con esta respuesta? – Mnementh

1

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

  • La aplicación es alta disponibilidad
  • Envío de e-mail es particularmente importante
  • El alcance de la aplicación es pequeña y el envío de e-mail es una gran parte de la misma
  • la aplicación se desplegará a un sitio que es remota y no harán más que los registros de depuración
  • puede recuperarse de algún subconjunto de las excepciones encapsulados en el mailException pero no en otras

En la mayoría de los casos, diría que solo ingrese el texto de la excepción y no pierda el tiempo de granularización de las excepciones ya bastante granulares.

10

En mi código, encuentro que MOST excepciones se filtran hasta una capa de IU donde son capturadas por mis manejadores de excepciones que simplemente muestran un mensaje al usuario (y escriben en el registro). Es una excepción inesperada, después de todo.

A veces, quiero ver una excepción específica (como parece querer hacer). Sin embargo, probablemente encontrará que esto es algo raro y que es indicativo de usar excepciones para controlar la lógica, que es ineficiente (lento) y a menudo desaprovechado.

Así, utilizando el ejemplo, si desea ejecutar alguna lógica especial cuando el servidor de correo electrónico no está configurada, es posible que desee añadir un método para el objeto EmailUtil como:

pública bool isEmailConfigured()

... llame eso primero, en lugar de buscar una excepción específica.

Cuando ocurre una excepción, realmente significa que la situación era completamente inesperada y el código no puede manejarlo, 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 vs excepciones-con-código-de-error-en-ellos, 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 mientras intentes ser consistente a lo largo de tu proyecto.

+0

¿También registra sus excepciones del lado del servidor? – pjp

+0

@php: Sí, buen punto, si es un código de servidor. Para aplicaciones de cliente reales (no web), generalmente también tengo la opción de registrar excepciones en el lado del cliente para la depuración. –

1

En lugar de usar excepciones, tiendo a devolver una lista de objetos de estado de métodos que pueden tener problemas para ejecutarse. 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 mal formateada"

El código de llamada decidiría qué para filtrar a la interfaz de usuario y que manejar solo.

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

Otra razón para usar 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, solo puede lanzar una excepción que debe manejarse antes de continuar.

Imagine que un usuario envía un correo electrónico que tenía una dirección de destino incorrecta y contenía el lenguaje que está bloqueando. ¿Lanza la excepción de correo electrónico mal formado, luego, después de que lo arreglan y lo vuelven a enviar, lanza una excepción de lenguaje incorrecto? Desde la perspectiva de la experiencia del usuario, tratar con todos a la vez es una mejor manera de hacerlo.

ACTUALIZACIÓN: combinando respuestas

@ Jonathan: Mi punto era que yo puedo evaluar la acción, en este caso el envío de un correo electrónico, y enviar de vuelta múltiples razones de fracaso. Por ejemplo, "dirección de correo electrónico incorrecta", "título del mensaje en blanco", etc.

Con una excepción, usted está limitado a filtrar el único problema y luego pedirle al usuario que lo vuelva a enviar y en ese momento averigüe sobre un segundo problema Este es un diseño de IU realmente malo.

Reinventando la rueda ... posiblemente. Sin embargo, la mayoría de las aplicaciones deberían analizar toda la transacción para brindar la mejor información posible al usuario. Imagine si su compilador se detuvo en el primer error. Luego corriges el error y presionas compilar de nuevo solo para que se detenga nuevamente por un error diferente. Qué dolor en el trasero. Para mí, ese es exactamente el problema con arrojar excepciones y, por lo tanto, la razón por la que dije usar un mecanismo diferente.

+1

Las excepciones son muy útiles y hacen que el código sea mucho más legible si se usa correctamente. El rendimiento de las características del lenguaje, como la excepción, está cambiando con cada lanzamiento de las máquinas virtuales modernas, por lo que debe medirlo cada vez frente a las cláusulas if (que claramente debe usar para verificar el resultado de un método). Los controles if para verificar el resultado de los métodos desordenan su código y dificultan su mantenimiento. No me malinterpreten: a veces los objetos de estado son una buena solución. Especialmente si manejas múltiples errores (como dijiste) son más útiles que las excepciones. Pero la decisión debe ser bien pensada. – Mnementh

2

@ Chris.Lively

usted sabe que puede pasar un mensaje en su excepción, o incluso los "códigos de estado". Estás reinventando la rueda aquí.

0

Tiendo a tener menos tipos de excepción, aunque no es realmente la manera OO de hacerlo. En cambio, pongo una enumeración a mis Excepciones personalizadas, que clasifica la Excepción. La mayoría de las veces tengo una Excepción base personalizada, que se aferra a un par de miembros, que pueden anularse o personalizarse en los tipos de Excepción derivados.

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

-1

sólo iría por

throw new exception("WhatCausedIt") 

si desea manejar sus excepciones, se puede pasar un código en lugar de "WhatCausedIt" una continuación reaccionan a las diferentes respuestas con una sentencia switch.

+0

En lugar de pasar un código en la excepción como parámetro, puede crear una excepción de subclase y usar instanceof. – Mnementh

0

Si bien se puede diferenciar la ejecución de código en busca excepción no importa si se hace por el "modo de jerarquía ExceptionType captura" o "si (...) si no ... excepción modo de código"

pero si está desarrollando un software que va a ser utilizado por otras personas, como una biblioteca, creo que es útil, cree sus propios tipos de excepciones para advertir a las otras personas que su software puede arrojar otras excepciones que las normales, y que es mejor atrapar y resolverlos.

Cuando uso una biblioteca y sus métodos simplemente ejecuto una 'Excepción', siempre me pregunto: ¿Qué puede causar esta excepción ?, ¿cómo debe reaccionar mi programa ?, si hay un JavaDoc quizá se explique la causa, pero debe ser de veces no hay un javadoc o la excepción no se explica. Demasiada tara puede evitarse con un WellChossenExceptionTypeName

0

Depende de si el código que capta la excepción necesita diferenciar entre excepciones o si solo 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 y escríbalo. Pero la mayoría de las veces los programadores usan las excepciones como una trampa para arrojar un error en la página web. En este caso, solo está desperdiciando esfuerzos al escribir una nueva excepción.

1

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

Puede lanzar diferentes excepciones dependiendo del problema. p.ej. Falta la dirección de correo electrónico = ArgumentException.

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

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

2

He encontrado que si necesita que el CÓDIGO decida qué hacer en función de la excepción devuelta, cree una excepción bien nombrada, subclases de un tipo de base común. El mensaje pasado debe considerarse "solo para ojos humanos" y demasiado frágil para tomar decisiones. Deje que el compilador haga el trabajo!

Si necesita pasar esto a una capa superior a través de un mecanismo que no conoce las excepciones comprobadas, puede envolverlo en una subclase llamada adecuada de RuntimeException (MailDomainException) que puede alcanzarse y la causa original actuó sobre.