2010-08-23 22 views
40

¿Existen directrices sobre la propagación de excepciones en Java?Directrices sobre la propagación de excepciones (en Java)

¿Cuándo agrega una excepción a la firma del método? Por ejemplo: si solo se lanza una excepción cuando falta un recurso esencial del programa, y ​​solo puede manejarse en el nivel superior, ¿lo propago a través de todos los métodos usando esta excepción a través de todos los métodos que usan el método erróneo?

¿Hay alguna buena práctica? ¿Alguna mala práctica?

Lo siento si estoy siendo vago, pero solo estoy buscando algunos consejos (generales) sobre el estilo de programación con respecto a las excepciones.

Respuesta

52

Directrices que me han ayudado en el pasado incluyen:

  • excepciones Throw cuando el método no puede controlar la excepción, y lo más importante, debe ser manejado por la persona que llama. Un buen ejemplo de esto sucede en la API de Servlet: doGet() y doPost() arrojan ServletException o IOException en ciertas circunstancias donde la solicitud no pudo leerse correctamente. Ninguno de estos métodos está en condiciones de manejar la excepción, pero el contenedor es (lo que da como resultado la página de error 50x en la mayoría de los casos).
  • Burbuja, la excepción si el método no puede manejarlo. Este es un corolario de lo anterior, pero aplicable a los métodos que deben captar la excepción. Si el método no puede manejar la excepción atrapada correctamente, entonces es preferible que se dispare.
  • Lanza la excepción de inmediato. Esto puede sonar vago, pero si se encuentra un escenario de excepción, es una buena práctica arrojar una excepción que indique el punto de falla original, en lugar de tratar de manejar la falla a través de códigos de error, hasta un punto considerado adecuado para arrojar la excepción . En otras palabras, intente minimizar la mezcla del manejo de excepciones con el manejo de errores.
  • O bien logre la excepción o búrlicelo, pero no haga ambos. El registro de una excepción a menudo indica que la pila de excepciones se ha desenrollado por completo, lo que indica que no se ha producido más borboteo de la excepción. Por lo tanto, no se recomienda hacer ambas cosas al mismo tiempo, ya que a menudo conduce a una experiencia frustrante en la depuración.
  • Utilice las subclases de java.lang.Exception (excepciones marcadas), excepto la persona que llama para manejar la excepción. Esto da como resultado que el compilador arroje un mensaje de error si la persona que llama no maneja la excepción. Sin embargo, ten cuidado, esto generalmente provoca que los desarrolladores "traguen" excepciones en el código.
  • Utilice las subclases de java.lang.RuntimeException (excepciones sin marcar) para señalar los errores de programación. Las clases de excepción que se recomiendan aquí incluyen IllegalStateException, IllegalArgumentException, UnsupportedOperationException etc. Nuevamente, hay que tener cuidado con el uso de clases de excepción como NullPointerException (casi siempre es una mala práctica lanzar una).
  • Utilice jerarquías de clases de excepción para comunicar información sobre excepciones en varios niveles. Al implementar una jerarquía, puede generalizar el comportamiento de manejo de excepciones en la persona que llama. Por ejemplo, podría usar una excepción raíz como DomainException que tiene varias subclases como InvalidCustomerException, InvalidProductException, etc. La advertencia aquí es que su jerarquía de excepciones puede explotar muy rápidamente si representa cada escenario excepcional por separado como una excepción por separado.
  • Evite atrapar excepciones que no puede manejar. Muy obvio, pero muchos desarrolladores intentan atrapar java.lang.Exception o java.lang.Throwable. Dado que todas las excepciones subclasificadas se pueden capturar, el comportamiento del tiempo de ejecución de la aplicación a menudo puede ser impreciso cuando se capturan clases de excepción "globales". Después de todo, uno no querría capturar OutOfMemoryError: ¿cómo debería manejarse una excepción?
  • Envuelva las excepciones con cuidado. Retirar una excepción restablece la pila de excepciones. A menos que se haya proporcionado la causa original al nuevo objeto de excepción, se pierde para siempre. Para preservar la pila de excepciones, se deberá proporcionar el objeto de excepción original al constructor de la nueva excepción.
  • Convierta las excepciones comprobadas en las no marcadas solo cuando sea necesario. Al envolver una excepción, es posible envolver una excepción marcada y arrojar una no marcada. Esto es útil en ciertos casos, especialmente cuando la intención es abortar el hilo que se está ejecutando actualmente. Sin embargo, en otros escenarios, esto puede causar un poco de dolor, ya que las comprobaciones del compilador no se realizan. Por lo tanto, adaptar una excepción marcada como una no marcada no está hecha a ciegas.
+4

No estoy de acuerdo con que los detalles se pierdan cuando se vuelve a lanzar una excepción. –

+0

@Thorbjorn, ah sí. No hay suficiente cafeína :-) He reformulado la última sección para reflejar la intención real. –

+0

@VineetReynolds "Usar subclases de java.lang.Exception (excepciones marcadas), cuando se exceptúa la persona que llama para manejar la excepción", ¿quiso decir "esperar"? – gumkins

2

Debe manejar el método lo antes posible, pero debe tener sentido. Si no tiene sentido que la excepción sea lanzada por su método, pero no puede manejarlo, envuélvalo en otra excepción y eche esta nueva excepción.

Una mala práctica sobre la excepción es atraparlos a todos (no es pokemon, ¡es java!) Así que evite catch(Exception e) o peor catch(Throwable t).

+0

¿Qué quiere decir con "envolverlo en otra excepción"? ¿Por qué no solo volver a lanzar la excepción original? – wen

+0

@Dennetik, en java tienes que atrapar excepciones marcadas o declarar que se lanzan. Inevitablemente lleva a envolver (o tragar, que es algo malo). De lo contrario, tu lista de lanzamientos se volverá incontrolable o te toparás con una interfaz que no te permite lanzar excepciones marcadas. – Yishai

+2

Porque en algún momento simplemente volver a lanzar la excepción original no tiene sentido, por ejemplo, si maneja una conexión a una base de datos para obtener una entidad y arroja una SQLException, no desea volver a lanzar una SQLException, sino más bien una de tu propia excepción, que tiene sentido en tu código. –

Cuestiones relacionadas