Вы находитесь на странице: 1из 20

Gestin de Excepciones

Excepciones. Categoras.
Las excepciones son el mecanismo por el cual pueden controlarse en un
programa Java las condiciones de error que se producen. Estas condiciones de
error pueden ser errores en la lgica del programa como un ndice de un array
fuera de su rango, una divisin por cero o errores disparados por los propios
objetos que denuncian algn tipo de estado no previsto, o condicin que no
pueden manejar.
La idea general es que cuando un objeto encuentra una condicin que no sabe
manejar crea y dispara una excepcin que deber ser capturada por el que le
llam o por alguien ms arriba en la pila de llamadas. Las excepciones son
objetos que contienen informacin del error que se ha producido y que heredan
de la clase Throwable o de la clase Exception. Si nadie captura la excepcin
interviene un manejador por defecto que normalmente imprime informacin que
ayuda a encontrar quin produjo la excepcin.
Existen dos categoras de excepciones:
Excepciones verificadas: El compilador obliga a verificarlas. Son todas las
que son lanzadas explicitamente por objetos de usuario.
Excepciones no verificadas: El compilador no obliga a su verificacin.
Son excepciones como divisiones por cero, excepciones de puntero nulo, o
ndices fuera de rango.

Generacin de excepciones
Supongamos que tenemos una clase Empresa que tiene un array de objetos
Empleado (clase vista en captulos anteriores). En esta clase podramos tener
mtodos para contratar un Empleado (aadir un nuevo objeto al array),
despedirlo (quilarlo del array) u obtener el nombre a partir del nmero de
empleado. La clase podra ser algo as como lo siguiente:
publicclassEmpresa{
Stringnombre;

Empleado[]listaEmpleados;
inttotalEmpleados=0;
...
Empresa(Stringn,intmaxEmp){
nombre=n;
listaEmpleados=newEmpleado[maxEmp];
}
...
voidnuevoEmpleado(Stringnombre,intsueldo){
if(totalEmpleados<listaEmpleados.length){
listaEmpleados[totalEmpleados++]
=newEmpleado(nombre,sueldo);
}
}
}
Observese en el mtodo nuevoEmpleado que se comprueba que hay sitio en el
array para almacenar la referencia al nuevo empleado. Si lo hay se crea el objeto.
Pero si no lo hay el mtodo no hace nada ms. No da ninguna indicacin de si la
operacin ha tenido xito o no. Se podra hacer una modificacin para que, por
ejemplo el mtodo devolviera un valor booleano true si la operacin se ha
completado con xito y false si ha habido algn problema.
Otra posibilidad es generar una excepcin verificada (Una excepcin no
verificada se producira si no se comprobara si el nuevo empleado va a caber o no
en el array). Vamos a ver como se hara esto.
Las excepciones son clases, que heredan de la clase genrica Exception. Es
necesario por tanto asignar un nombre a nuestra excepcin. Se suelen asignar
nombres que den alguna idea del tipo de error que controlan. En nuestro ejemplo
le vamos a llamar CapacidadEmpresaExcedida.
Para que un mtodo lance una excepcin:
Debe declarar el tipo de excepcin que lanza con la clusula throws, en su
declaracin.
Debe lanzar la excepcin, en el punto del cdigo adecuado con la
sentencia throw.
En nuestro ejemplo:

voidnuevoEmpleado(String
nombre,intsueldo)throwsCapacidadEmpresaExcedida {
if(totalEmpleados<listaEmpleados.length){
listaEmpleados[totalEmpleados++]
=newEmpleado(nombre,sueldo);
}

elsethrownewCapacidadEmpresaExcedida(nombre);
}
Adems, necesitamos escribir la
clase CapacidadEmpresaExcedida.Sera algo as:
publicclassCapacidadEmpresaExcedidaextendsExceptio
n{
CapacidadEmpresaExcedida(Stringnombre){
super("Noesposibleaadirelempleado"+
nombre);
}
...
}
La sentencia throw crea un objeto de la
clase CapacidadEmpresaExcedida. El constructor tiene un argumento (el
nombre del empleado). El constructor simplemente llama al constructor de la
superclase pasndole como argumento un texto explicativo del error ( y el
nombre del empleado que no se ha podido aadir).
La clase de la excepcin puede declarar otros mtodos o guardar datos de
depuracin que se consideren oportunos. El nico requisito es que extienda la
clase Exception. Consultar la documentacin del API para ver una descripcin
completa de la clase Exception.
De esta forma se pueden construir mtodos que generen excepciones.

Captura de excepciones
Con la primera versin del mtodo nuevoEmpleado (sin excepcin) se invocara
este mtodo de la siguiente forma:

Empresaem=newEmpresa("LaMundial");
em.nuevoEmpleado("AdnPrimero",500);
Si se utilizara este formato en el segundo caso (con excepcin) el compilador
producira un error indicando que no se ha capturado la excepcin verificada
lanzada por el mtodo nuevoEmpleado. Para capturar la excepcin es utiliza la
construccin try / catch, de la siguiente forma:
Empresaem=newEmpresa("LaMundial");
try{
em.nuevoEmpleado("AdnPrimero",500);
}catch(CapacidadEmpresaExcedidaexc){
System.out.println(exc.toString());
System.exit(1);
}
Se encierra el cdigo que puede lanzar la excepcin en un bloque try /
catch.
A continuacin del catch se indica que tipo de excepcin se va a capturar.
Despus del catch se escribe el cdigo que se ejecutar si se lanza la
excepcin.
Si no se lanza la excepcin el bloque catch no se ejecuta.
El formato general del bloque try / catch es:
try{
...
}catch(Clase_Excepcionnombre){...}
catch(Clase_Excepcionnombre){...}
...
Observese que se puede capturar ms de un tipo de excepcin declarando ms de
una sentencia catch. Tambin se puede capturar una excepcin genrica (clase
Exception) que engloba a todas las dems.
En ocasiones el cdigo que llama a un mtodo que dispara una excepcin
tampoco puede (o sabe) manejar esa excepcin. Si no sabe que hacer con ella
puede de nuevo lanzarla hacia arriba en la pila de llamada para que la gestione

quien le llamo (que a su vez puede capturarla o reenviarla). Cuando un mtodo


no tiene intencin de capturar la excepcin debe declararla metdiante la clusula
throws, tal como hemos visto en el mtodo que genera la excepcin.
Supongamos que, en nuestro ejemplo es el mtodo main de una clase el que
invoca el mtodo nuevoEmpleado. Si no quiere capturar la excepcin debe hacer
lo siguiente:
publicstaticvoidmain(String[]
args)throwsCapacidadEmpresaExcedida{
Empresaem=newEmpresa("LaMundial");
em.nuevoEmpleado("AdnPrimero",500);
}

Clusula finally
La clusula finally forma parte del bloque try/ catchy sirve para
especificar un bloque de cdigo que se ejecutar tanto si se lanza la excepcin
como si no. Puede servir para limpieza del estado interno de los objetos afectados
o para liberar recursos externos (descriptores de FICHERO , por ejemplo). La
sintaxis global del bloque try/ catch/ finallyes:
try{
...
}catch(Clase_Excepcionnombre){...}
catch(Clase_Excepcionnombre){...}
...
finally{...}

http://www.cc.uah.es/jlcastillo/POO/media/JavaCap4.pdf
http://www.mundojava.net/excepciones.html?Pg=java_inicial_4_6.html

http://codehero.co/manejo-de-excepciones-parte/

http://www.cursohibernate.es/doku.php?id=patrones:excepciones

Excepciones en Java
Empecemos recordando los dos tipos de excepciones que hay en Java 1)
Excepciones Checked: Objetos de la clase Exception o cualquier otra clase que hereda
de ella, excepto si heredan de RuntimeException.
Excepciones Unchecked: Objetos de la clase RuntimeException o de cualquiera otra
clase que herede de ella.

Excepciones Checked
Las excepciones Checked son aquellas que deben declararse en el mtodo mediante la
palabra throws y que obligan al que lo llama a hacer un tratamiento de dicha excepcin.

Son excepciones Checked cualquier objeto de la clase Exception o de cualquier otra clase que
herede de ella, excepto si el objeto es de la clase RuntimeException o cualquier otra clase que
herede de sta ltima.
1:
2:
3:
4:
5:
6:
7:

public class Matematicas {


public double dividir(double a, double b) throws Exception {
if (b == 0) {
throw new Exception("El argumento b no puede ser 0");
}

9:

return a / b;

8:

El mtodo dividir lanza en la lnea 4 una Checked Exception por lo tanto el mtodo lo declara
mediante throws.
Ahora cualquiera que llame al mtodo dividir est obligado a tratar la excepcin Exception de
dos formas:
Mediante un try-cath:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

public class Main {


public static void main(String[] args) {
Matematicas matematicas=new Matematicas();
try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {
//Tratar la excepcin
}
}
}

En las lneas 4,6,7 y 8, se usa un try-catch para atrapar la excepcin que puede
producir la llamada el mtodo dividir.
Declarndo a su vez en el mtodo que puede lanzar dicha excepcin:

1:
2:
3:

public class Main {


public static void main(String[] args) throws Exception {
Matematicas matematicas=new Matematicas();

4:

double c=matematicas.dividir(-1.6, 0);

5:

6:
7:

En la lnea 2 vemos como se declaraque el mtodo main puede lanzar una excepcin
del tipo Exception ya que dividir lo lanza y no se atrapa con un try-catch.

Excepciones Unchecked
Las excepciones Unchecked son aquellas que no se declaran en el mtodo y que no obligan al
que lo llama a hacer un tratamiento de dicha excepcin.
Son excepciones Unchecked
clase RuntimeException.

todas

aquellas

excepciones

que

heredan

de

la

public class Matematicas {


public double dividir(double a, double b) {
3:
if (b == 0) {
4:
throw new RuntimeException("El argumento b no puede ser
0");
5:
}
1:
2:

6:
7:

return a / b;

8:
9:

El mtodo dividir lanza en la lnea 4 una unchecked Exception por lo que no es necesario hacer
nada especial con ella.
1:
2:
3:
4:
5:

public class Main {


public static void main(String[] args) {
Matematicas matematicas=new Matematicas();
double c=matematicas.dividir(-1.6, 0);

6:
7:

Como la excepcin que lanza dividir es Unchecked no necesitamos tratarla en el


mtodo main de ninguna forma especial.

Cuando usar excepciones Checked o Unchecked y que hacer con


ellas
Una vez visto como Java trata las excepciones de ambos tipos pasemos a explicar cuando
debemos usar las de un tipo u otro.

Checked Exceptions
Las excepciones Checked son condiciones excepcionales del flujo del programa pero que no son
debido a un error del propio programa. Es decir si se lanza una excepcin checked el programa no
tiene ningn tipo de error y sigue funcionando correctamente, simplemente se ha producido una
situacin excepcional que hemos marcado como una excepcin.

Por ejemplo si tenemos una funcin que borra ficheros y al ir a borrarlo , dicho FICHERO ya no
existe, deberemos lanzar una FileNotFoundException indicando que el fichero no existe. Que
el fichero ya no exista no es ningn error en el programa, puede haberse borrado justo un instante
antes , sin embargo, si que es una situacin excepcional porque la mayora de las veces cuando
vayamos a borrarlo deber estar el fichero si hemos acabado de seleccionarlo.
De ah que al ser usa situacin legitima del programa pero poco probable los creadores de Java
han decidido que es necesario declararla en el mtodo y que sea obligatorio tratarla. Las Checked
Exceptions no tienen nada de malo y son muy tiles para realizar correctamente los programas.
La Checked Exceptions forman parte del flujo lgico de nuestro programa y al programar debemos
tenerlas en cuenta y tratarlas adecuadamente no vindolas como un problema del que debemos
deshacernos.
Aunque hemos puesto el mismo ejemplo del mtodo dividir tanto para explicar las excepciones
Checked o Uncheked tras la explicacin debe quedar claro que la excepcin que debe lanzar el
mtodo dividir debe ser del tipo unchecked.

Unchecked Exceptions
Este tipo de error es mucho mas sencillo de entender. Una excepcin unchecked es aquella que se
lanza cuando hay un error en el programa.
Por ejemplo en el caso anterior de la divisin por cero, es un error de programacin que alguien
nos pase como dividendo un cero, en ese caso lanzaremos un RuntimeException.
Al ser las unchecked Exceptions errores en el programa , poco podemos hacer por arreglarlas. Por
ello no es obligatorio tratarlas con un try-catch. Lo nico que podemos hacer en la mayora de
casos es hacer que el programa acabe fallando y que se muestre un mensaje de error al usuario.
Es decir, si el programa funciona mal , es mejor que no siga funcionando antes que hacer que
contine funcionado pero usando datos errneos, ya que en ese caso los resultados que generara
tambin podran ser errneos.
Las unchecked exceptions no debemos tratarlas ya que no forma parte de la lgica de la aplicacin
y no debemos hacer nada con ella, simplemente debemos preocuparnos en el mensaje que
acabar llegando al usuario. En una aplicacin Web es tan sencillo como tener pginas de error
personalizadas.

El problema con las excepciones


Hasta ahora hemos visto los dos tipos de excepciones que hay , como las trata el compilador de
Java y cuando usar una u otra. Sin embargo hay un problema con las excepciones que hace que
no se traten de forma correcta.

El problema de las excepciones es que en muchas APIs de Java se lanzan checked cuando
deberan ser unchecked.
Por ejemplo, en el API de JDBC al ejecutar una consulta mediante executeQuery() se lanzar la
excepcin java.sql.SQLException que es de tipo Checked si la SQL es erronea. Acaso eso
no es un error de programacin y por lo tanto debera ser de tipo unchecked? Es decir que
tenemos un problema ya que deberemos tratar excepciones Checked pero no se pueden hacer
ningn tratamiento para solucionar lo que gener dicha excepcin.
El verdadero problema de Java es que muchas API lanzan Checked exceptions cuando deberan
haber sido uncheked exceptions.
Como acabamos de decir, eso nos lleva a los programadores a capturar dichas excepciones y
tener que tratarlas. Pero como tratamos dichas excepciones Checked si realmente son errores de
programa y por lo tanto excepciones unchecked? Pues solo hay una forma de hacerlo, es
transformando las excepciones Checked en unchecked.
1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {
throw new RuntimeException("Fallo al llamar a 'dividir'",ex)
}

Vemos en la lnea 4 como lanzamos una nueva excepcin del tipo unchecked pero dentro contiene
la excepcin original que se ha producido ya que se le pasa como argumento. Con sto hemos
solucionado el problema. Pero vuelvo a repetir sta construccin solo debe hacerse con aquellas
excepciones checked que consideramos que deberan haber sido unchecked.
Esta construccin tan sencilla que consiste en que las excepciones checked ,pero que deberan
haber sido uncheked, trasformarlas en excepciones uncheked nos soluciona prcticamente todos
nuestros problemas.
1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {
throw new RuntimeException("Fallo al llamar a 'dividir'",ex)
}

Mas problemas
Veamos ahora otro problema de las excepciones.Hay excepciones unchecked , que segn su
significado, deberan haber sido del tipo checked ya que no son debido a errores del programa (lo
contrario del caso anterior).
La excepcin ConstraintViolationException se lanza cuando alguna validacin de una
entidad no se ha cumplido. Se suele utilizar para indicar que el usuario ha introducido algn dato

erroneo en la aplicacin. Entonces, porqu es una excepcin unchecked? Segn lo que se est
explicando no hay duda de que debera ser del tipo Checked ya que no se lanza por un error de
programacin sino a causa de un dato mal introducido por el usuario.
El problema que se genera con sto es que la excepcin ConstraintViolationException no
sabemos que mtodo la va a lanzar a no ser que nos leamos la documentacin, pero es importante
capturarla para poder mostrar un mensaje al usuario. Si hubiera sido declarada como Checked, el
propio compilador nos avisara de cuando capturarla. Todo sto nos puede llevar a que el usuario
acabe viendo nuestra pgina de error de la aplicacin simplemente porque se ha dejado un campo
sin rellenar.
Otro problema de Java es que hay APIs que lanzan UnChecked Exceptions cuando deberan haber
sido Cheked Exceptions.
La solucin a este problema consiste simplemente en leerse la documentacin para ver cuando se
lanza una excepcin unchecked , que debera haber sido Checked, para capturarla y hacer el
correcto tratamiento con ella.
Mas informacin sobre la excepcin ConstraintViolationException y como solucionar el
problema lo tenemos en Excepciones

Formas errneas de tratar las excepciones


Veamos ahora una serie de errores que se cometen al tratar las excepciones.

Perder la excepcin original


Quizs otro origen del desconocimiento de las excepciones es que hasta Java 1.4 no se poda
encapsular una excepcin dentro de otra. Lo podemos ver en la clase Throwable de la que
hereda Exception.
Throwable en Java 1.3: No existen un constructor que acepte como argumento otra
excepcin

ni

el

mtodo Throwable

getCause() que

obtiene

la

excepcin

encapsulada.
Throwable en Java 1.4: Ya dispone de un constructor al que pasarle otra excepcin y el
mtodo Throwable getCause().
Esto ltimo nos ha llevado a soluciones errneas como la siguiente:
1:
2:
3:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {

throw new RuntimeException("Fall al llamar a 'dividir':"


ex.getMessage());
5: }
4:

En la lnea 4 vemos como se crea una RuntimeException pero de la excepcin original se ha


pedido la traza completa y solo vamos a conseguir el mensaje de error, pero las excepciones
pueden tener mucha mas informacin que simplemente el mensaje y la traza.
Por

ejemplo

la

excepcin SQLException dispone

de

los

mtodos getSQLState() y getErrorCode() que contiene informacin sobre el error concreto


que ha ocurrido en la base de datos. Usando el cdigo anterior tambin lo habramos perdido.

Crear una excepcin inutil


Otro segundo error es crear una nueva excepcin generica 2) que no aporta nada respecto
a RuntimeException 3) y usarla en vez de RuntimeException
1:
2:
3:
4:
5:

public class MiExcepcion extends RuntimeException {


public MiExcepcion (String msg) {
super(msg);
}
}

Creando una excepcin personalizada que no aporta nada.


1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {
throw new MiExcepcion ("Fall al llamar a 'dividir'.");
}

En la lnea 4 se lanza la nueva excepcin MiExcepcion que no hace nada que no hiciera
ya RuntimeException e incluso seguimos perdiendo la excepcin original.

Pasar el problema hacia arriba


La siguiente forma errnea de tratar la excepciones es simplemente hacer que el mtodo superior
a su vez declare que lanza esas excepciones checked pero que deberan haber sido uncheked.
Con sto lo nico que hacemos es expandir el problema hacia arriba sin solucionarlo.
1:
2:
3:
4:
5:

public class Main {


public static void main(String[] args) throws Exception {
Matematicas matematicas=new Matematicas();
}

6:
7:

double c=matematicas.dividir(-1.6, 0);

En la lnea 2 vemos ahora como el mtodo Main ahora tambin lanza una excepcin checked.

Ignorarla
Este es el peor error que podemos cometer al tratar una excepcin.Consiste simplemente en
ignorar la excepcin y que contine la ejecucin del programa. Esto es tan peligroso ya que si se
ha producido algn fallo en el programa lo ms seguro es hacer que se detenga cuanto antes y no
seguir haciendo operaciones con datos que quizs sean errneos.
1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {
}

Vemos en la lnea 4 como no se realiza ninguna accin al capturar la excepcin, por lo tanto la
ejecucin seguir como si no hubiera pasado nada.

Log
Acabamos de ver en el apartado anterior que nunca

4)

se debe ignorar la excepcin. Una forma de

ignorarla pero que aparenta ser mejor solucin es guardar en el log la excepcin que se ha
producido pero sin hacer nada mas.
try {
double c=matematicas.dividir(-1.6, 0);
3: } catch (RuntimeException ex) {
4:
Logger.getLogger(Main.class.getName()).log(Level.SEVERE,
ex);
5: }
1:
2:

null,

En la lnea 4 guardamos en el log la excepcin pero el programa sigue ejecutndose. Como ya


hemos comentado no debera seguir la ejecucin del programa puesto que los datos pueden haber
quedado en un estado errneo.
La idea de guardar en el log la excepcin es buena por si misma. Sin embargo no suele ser
necesario guardarla explcitamente ya que en muchas ocasiones ya se guarda automticamente.
Por ejemplo en aplicaciones Web , el propio contenedor al detectar

5)

una excepcin guardar en el

log la excepcin que se ha producido.

Consola
Otra forma erronea de guardar las excepciones consiste en mostrar la traza del error por la
consola.

1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (RuntimeException ex) {
ex.printStackTrace();
}

En la lnea 4 mostramos por la consola la traza de la excepcin pero el programa sigue


ejecutndose. Como ya se ha dicho no debera seguir la ejecucin del programa puesto que los
datos pueden haber quedado en un estado errneo.
En aplicaciones Web o aplicaciones de Ventanas , esta opcin tiene menos sentido aun que la
opcin del log, ya que guardando la traza en un fichero de log est mucho ms accesible para
poder averiguar el origen del problema que mostrndolo por consola ya que la consola la puede
cerrar el usuario y perder toda la traza o simplemente que no tengamos acceso a la consola.

Imprimirla
Por ltimo pero no por ello menos usada est la tcnica de imprimir el mensaje de la excepcin.
1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (RuntimeException ex) {
System.out.println("Fall al dividir");
}

Esta forma tiene los mismos problemas del anterior de imprimirla por consola pero sta es aun
peor, hemos perdido toda la informacin de la excepcin.

Mejoras en el tratamiento de excepciones


Ya hemos visto como es la forma correcta de tratar las excepciones Checked que realmente
deberan ser unchecked:
1:
2:
3:
4:
5:

try {
double c=matematicas.dividir(-1.6, 0);
} catch (Exception ex) {
throw new RuntimeException("Fallo al llamar a 'dividir'",ex)
}

Este cdigo tiene unas pegas al respecto de las trazas que se generara por pantalla

6)

cuando se

produce una excepcin.


Si ejecutamos el cdigo se produce la siguiente traza:
Exception in thread "main" java.lang.RuntimeException: Fallo al llamar
a 'dividir'
1:

2:
3:
4:
5:

at
Caused
at
at

ejemplo.Main.main(Main.java:17)
by: java.lang.Exception: El argumento b no puede ser 0
ejemplo.Matematicas.dividir(Matematicas.java:14)
ejemplo.Main.main(Main.java:15)

Como podemos ver en la traza, se muestran dos excepciones, la excepcin original en la lnea 3 y
la RuntimeExcepcion que encapsula a la excepcin original en la lnea 1. Esto es inevitable as
que por ahora lo vamos a asumir.
El

problema

viene

si

el

mtodo dividir puede

lanzar

tanto

una Exception como

una RuntimeException.
Veamos el cdigo modificado de dividir para que en caso de que algn nmero sea negativo se
produzca una RuntimeException:
public class Matematicas {
public double dividir(double a, double b) throws Exception {
3:
if (a<0) {
4:
throw new RuntimeException("El argumento a no puede ser
negativo");
5:
}
6:
if (b<0) {
7:
throw new RuntimeException("El argumento b no puede ser
negativo");
8:
}
1:
2:

9:
10:

if (b == 0) {
throw new Exception("El argumento b no puede ser 0");
}

11:
12:
13:
14:

15:
16:

return a / b;

Vemos en las lneas de la 3 a la 8 como ahora tambin se lanza un RuntimeException.


Si volvemos ahora a ejecutar el programa se genera la siguiente traza de error:
Exception in thread "main" java.lang.RuntimeException: Fallo al llamar
a 'dividir'
2:
at ejemplo.Main.main(Main.java:17)
3: Caused by: java.lang.RuntimeException: El argumento a no puede ser
negativo
4:
at ejemplo.Matematicas.dividir(Matematicas.java:14)
5:
at ejemplo.Main.main(Main.java:15)
1:

Ahora
la
traza
si
que
ha
quedado
un
poco
mal.Hemos
encapsulado
una RuntimeException (lnea 3) dentro de otra RuntimeException (lnea 1) lo que tiene muy
poco sentido. Es decir que la traza ha quedado poco clara cuando no hay necesidad para ello. Esto

ocurre ya que RuntimeException hereda de Exception por lo que el catch tambin atrapa
la RuntimeException y la encapsula en otra RuntimeException.
La solucin a sto, es bastante sencilla.Si nos llega una RuntimeException simplemente la
volvemos a lanzar en vez de encapsularla.
public class Main {
public static void main(String[] args) {
3:
Matematicas matematicas=new Matematicas();
4:
try {
5:
double c=matematicas.dividir(-1.6, 0);
6:
} catch (RuntimeException ex) {
7:
throw ex;
8:
} catch (Exception ex) {
9:
throw new RuntimeException("Fallo
'dividir'",ex);
10:
}
11:
}
12: }
1:
2:

al

llamar

En la lnea 6 ahora capturamos la RuntimeException y al tratarla simplemente relanzamos la


misma excepcin (lnea 7).
Si ahora volvemos a ejecutar el cdigo, la traza resultante es:
Exception in thread "main" java.lang.RuntimeException: El argumento a
no puede ser negativo
2:
at ejemplo.Matematicas.dividir(Matematicas.java:14)
3:
at ejemplo.Main.main(Main.java:15)
1:

Es decir que ahora la traza para una RuntimeException es como debera ser ,ya que no queda
encapsulada por ninguna otra excepcin.
Por los ejemplos puede parecer un poco exagerado querer que no se encapsulen las excepciones
pero pongo aqu un ejemplo de excepciones en Hibernate:
Exception in thread "main" org.hibernate.MappingException: Could not get
constructor for org.hibernate.persister.entity.SingleTableEntityPersister
at
org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFac
toryImpl.java:185)
at
org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersist
er(PersisterFactoryImpl.java:135)
at
org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:
367)

at
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:17
40)
at
curshibernatet03e01.CursHibernateT03E01.main(CursHibernateT03E01.java:23)
Caused by: org.hibernate.HibernateException: Unable to instantiate
default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
at
org.hibernate.tuple.entity.EntityTuplizerFactory.constructTuplizer(Entity
TuplizerFactory.java:138)
at
org.hibernate.tuple.entity.EntityTuplizerFactory.constructDefaultTuplizer
(EntityTuplizerFactory.java:188)
at
org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:34
1)
at
org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEnt
ityPersister.java:502)
at
org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTa
bleEntityPersister.java:144)
Method)

at

sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native

at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAc
cessorImpl.java:57)
at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConst
ructorAccessorImpl.java:45)
at
java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at
org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFac
toryImpl.java:163)
... 4 more
Caused by: java.lang.reflect.InvocationTargetException
at

sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native

Method)
at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAc
cessorImpl.java:57)
at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConst
ructorAccessorImpl.java:45)
at
java.lang.reflect.Constructor.newInstance(Constructor.java:525)

at
org.hibernate.tuple.entity.EntityTuplizerFactory.constructTuplizer(Entity
TuplizerFactory.java:135)
... 13 more
Caused by: org.hibernate.PropertyNotFoundException: Could
getter for domicilio in class curshibernatet03e01.Cliente

not

find

at
org.hibernate.property.BasicPropertyAccessor.createGetter(BasicPropertyAc
cessor.java:316)
at
org.hibernate.property.BasicPropertyAccessor.getGetter(BasicPropertyAcces
sor.java:310)
at org.hibernate.mapping.Property.getGetter(Property.java:320)
at
org.hibernate.tuple.entity.PojoEntityTuplizer.buildPropertyGetter(PojoEnt
ityTuplizer.java:436)
at
org.hibernate.tuple.entity.AbstractEntityTuplizer.<init>(AbstractEntityTu
plizer.java:200)
at
org.hibernate.tuple.entity.PojoEntityTuplizer.<init>(PojoEntityTuplizer.j
ava:82)
... 18 more
Realmente la informacin mas til la encontramos justamente en la primera excepcin que se
produce. Sin embargo est justamente al final de toda la traza:
PropertyNotFoundException: Could not find a getter for domicilio in class
curshibernatet03e01.Cliente
As que si no se hubiera encapsulado la excepcin se vera en la primera lnea en vez de ir a
buscarla al final de la traza.

La solucin definitiva
La solucin definitiva es que las excepciones checked tenga tambin una traza limpia como las
unchecked. Antes hemos comentado que es imposible pero hay un truco en Java que permite
hacerlo, no voy a explicar como funciona el truco simplemente voy a explicar como hacerlo.
Se debe crear la siguiente clase:
1:
2:
3:

public

class RelanzadorExcepciones {

public static RuntimeException lanzar( Exception ex){


4:

RelanzadorExcepciones.<RuntimeException>lanzarComoUnchecked(ex);
5:

6:
throw new AssertionError("Esta lnea
Java no lo sabe");
7:
}

nunca se ejecutar pero

8:

9:
private
static
<T
extends
lanzarComoUnchecked(Exception toThrow) throws T{
10:
throw (T) toThrow;
11:
}
12: }

Exception>

void

Ahora nuestro cdigo Main se modificar quedando de la siguiente forma:


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

public class Main {


public static void main(String[] args) {
Matematicas matematicas=new Matematicas();
try {
double c=matematicas.dividir(3, 0);
} catch (Exception ex) {
RelanzadorExcepciones.lanzar(ex);
}
}
}

Vemos como ahora para relanzar la excepcin en la lnea 22 usamos el nuevo mtodo que hemos
creado RelanzadorExcepciones.lanzar.
Si ejecutamos ahora la aplicacin y vemos la traza, queda de la siguiente forma:
Exception in thread "main" java.lang.Exception: El argumento b no puede
ser 0
at ejemplo.Matematicas.dividir(Matematicas.java:21)
at ejemplo.Main.main(Main.java:15)
Es decir que nicamente se ve la excepcin checked sin que quede encapsulada por nadie.!!
Por fin con este ultimo truco hemos conseguido simplificar la traza con todas las excepciones.

Referencias
Java theory and practice: The exceptions debate
Effective Java (2nd Edition)
Thinking in Java, 4th edition
Expert One-on-One J2EE Design and Development
The Java Tutorials.Unchecked ExceptionsThe Controversy
Throwing Checked Exceptions Like Unchecked Exceptions in Java
13 Exceptional Exception Handling Techniques

Вам также может понравиться