Podemos considerar que una Excepción en programación es una situación poco habitual que provoca resultados inesperados o incoherentes en nuestros métodos, pero que es contemplada en el análisis, diseño y construcción de nuestro sistema : el sistema se puede recuperar de estas situaciones.
Como ejemplos podemos citar envíos duplicados de información, una caída de nuestra base de datos, información inválida o incosistente como un número de teléfono con un formato incorrecto…
Para mantener códigos robustos que manejen estas situaciones, los lenguajes de programación incorporan mecanismos para el manejo de excepciones como parte de sus estructuras de control.
Y las situaciones poco habituales que provocan resultados inesperados o incoherentes y que no controlamos ? Eso es un error en tiempo de ejecución en nuestro sistema, que puede desembocar en una inconsistencia de datos en nuestra base de datos o en la finalización inesperada de nuestro sistema.
Un buen indicador de la calidad de un sistema software es comprobar cómo responde cuando se producen fallos, ya sean esperados y controlados (excepciones) o inesperados e incontrolados (errores).
Excepciones en Java
En el caso de Java se utilizan bloques try - catch - finally, throw y throws, y las subclases de java.lang.Exception. Un método lanzarán (mediante un throw) una excepción (una clase que hereda java.lang.Exception) provocando que se abandone el flujo de ejecución normal y cediendo el control al bloque en el que se capturará (en un bloque try - catch - finally). En la declaración del método se incluye throws para avisar de que puede lanzar una excepción.
Existen muchas excepciones predefinidas en Java, pero también nosotros podemos crear excepciones particulares a nuestros sistemas : basta crear una clase que extienda de java.lang.Exception.
Existen dos grandes tipos de excepciones en Java :
- Checked Exceptions (excepciones controladas). Se corresponden a errores previstos, controlados en el codigo y por tanto permite al sistema recuperarse. Son lo que hemos definido anteriormente como excepciones. El compilador Java es una gran ayuda ya que te obliga a capturarlas en un bloque try - catch - finally o a declarar que el método puede devolver una excepción (declarando un throws).
- Unchecked Exceptions (excepciones no controladas). Son excepciones no previstas ni controladas, y por tanto puede provocar inconsistencia de datos y la finalización inesperada del sistema : lo que hemos definido anteriormente como errores en tiempo de ejecución. En Java se implementan como subclases de java.lang.RuntimeException (que a su vez hereda de java.lang.Exception) y el compilador no nos obliga a capturarlas ni a declarar que nuestros métodos pueden lanzarlas. NullPointerException o IllegalArgumentException son dos ejemplos de estas excepciones.
No olvides utilizar la parte finally de los bloques try - catch - finally para liberar recursos como conexiones o archivos.
Manejo de Excepciones en una arquitectura Java
Al invocar un método deberíamos obtener como resultado o bien el resultado normal de la ejecución o bien no hacer absolutamente nada. Las excepciones nos servirán para comunicar a las capas superiores información sobre por qué no se ha hecho nada si fuese necesario.
La utilización de bloques try - catch - finally es más costoso en términos de tiempo de ejecución y recursos que la utilización de bloques if - else.
- Por tanto es recomendable utilizar excepciones para controlar el flujo, es mejor utilizar los mecanismos de control de flujo ya existentes que consumen menos y son más fácilmente mantenibles.
- Tampoco es recomendable capturar una excepción en un bloque catch y no hacer nada, o no hacer nada más que lanzarla nuevamente.
Es aconsejable que las excepciones no rompan la encapsulación. Por ejemplo si en una capa inferior se produce una excepción (por ejemplo una SQLException en la capa de persistencia), a la capa superior no le interesa conocer los detalles de implementación, sino:
- si se puede recuperar del error, es aconsejable transformar la excepción original en otra excepción controlada o checked con la información necesaria para recuperar que la capa superiro se pueda recuperar.
- o si no puede recuperarse del error pasamos a la capa superior una excepción no controlada o unchecked si no se debe continuar el flujo normal, o bien un resultado nulo si no se quiere hacer nada especial.
Sólo deberíamos de crear excepciones propias cuando aporten algo útil como información extra cuando sean capturadas o comportamientos propios (como un tratamiento especial en un log).
Al capturar excepciones también capturamos las que heredan de ésta. Por tanto al capturar una excepción del tipo java.lang.Exception también estamos capturando todas las unchecked (ya que heredan de java.lang.RuntimeException y ésta hereda de java.lang.Exception). Hay que tener cuidado de si esto es realmente lo que queremos.
Por todo lo dicho anteriormente, la gestión de las excepciones nos debería de servir para recuperarnos ante errores esperados. Pero deberíamos tener en cuenta que pueden existir errores no controlados. Podríamos gestionar estos errores en un único punto, desviando todas las excepciones no capturadas a un action donde se tratarán (típicamente presentación de una página de error con un mensaje y las acciones permitidas para el usuario, así como la auditoría del error). Podemos indicar en el web.xml esta redirección :
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/gestionErrores.do</location>
</error-page>
Enlaces recomendados