Vous êtes sur la page 1sur 29

9

Controlar

excepciones
Conceptos fundamentales:
La jerarqua de excepciones.
Utilizar try y c atc h.
Comprender los efectos de una excepcin sin capturar.
Utilizar varias instrucciones ca tch.
Capturar excepciones de subclases.
Anidar bloques try.
Generar una excepcin.
Conocer los miembros de Th rowable.
Utilizar final ly y thr ows.
Excepciones integradas de Java.
Crear clases de excepcin personalizadas.
En este captulo analizaremos el control de excepciones. Una excepcin es un error
producido en tiempo de ejecucin. Por medio del subsistema de control de excepciones
de Java, puede, de forma estructurada y controlada, controlar errores de tiempo de ejecu-
cin. Aunque la mayora de lenguajes de programacin modernos ofrecen alguna forma
de control de excepciones, en Java es ms limpio y flexible.
lllal 9. Controlar excepciones
Una de las principales ventajas del control de excepciones es que automatiza gran
parte del cdigo de control de errores que antes haba que aadir a mano a un programa.
Por ejemplo, en algunos lenguajes informticos antiguos, se devuelven cdigos de
error cuando un mtodo falla, valores que deben comprobarse manualmente en cada
invocacin del mtodo. Es un enfoque tedioso y proclive a errores. El control de excep-
ciones racionaliza el control de errores ya que permite al programa definir un bloque
de cdigo, denominado controlador de excepciones, que se ejecuta automticamente
cuando se produce un error. No es necesario comprobar manualmente el xito o fallo de
cada operacin o invocacin de mtodo concreto. Si se produce un error, el controlador
de excepciones lo procesa. Otro motivo de la importancia del control de excepciones en
Java es que define excepciones estndar para errores de programacin comunes, como
la divisin por cero o de archivos no encontrados. Para responder a estos errores, su
programa debe buscar estas excepciones y corregirlas. Adems, la biblioteca del API de
Java usa excepciones de forma amplia.
Para ser programador de Java con xito, tendr que ser capaz de navegar por el
subsistema de control de excepciones.
La jerarqua de excepciones
En Java, todas las excepciones se representan por medio de clases. Todas las clases
de excepcin se derivan de Throwable. Por tanto, cuando se produce una excepcin,
se genera un objeto de un tipo de clase de excepcin. Throwable tiene dos subclases
directas: Exception y Error. Las excepciones de tipo Error estn relacionadas con
errores producidos en la propia mquina virtual de Java y no en el programa. No las
puede controlar y su programa tampoco. Por tanto, no las describiremos en el libro.
Los errores de la actividad de un programa se representan por medio de subclases
de Exception. Por ejemplo, la divisin por cero, los lmites de matriz y los errores de
archivo entran en esta categora. Por lo general, su programa debe controlar las excep-
ciones de este tipo. Una subclase importante de Exception es RuntimeExcepti on,
que se usa para representar distintos tipos de errores de tiempo de ejecucin.
Fundamentos del control de excepciones
El control de excepciones de Java se gestiona a travs de cinco palabras clave: try,
catch, throw, throws y finally. Forman un subsistema interrelacionado en el que
el uso de una implica el de otra. A lo largo del captulo veremos detalladamente cada
una de estas palabras clave. Sin embargo, conviene conocer su funcin en el control de
excepciones, como veremos a continuacin.
Las instrucciones de programa que use para monitorizar excepciones se incluyen en
un bloque try. Si se produce una excepcin en este bloque, se genera. Su cdigo puede
capturarla por medio de ca tch y procesarla de forma racional. Las excepciones generadas
Java 7 1111
por el sistema se generan automticamente en el sistema de tiempo de ejecucin de Java.
Para generar una excepcin manualmente, debe usar la palabra clave throw. En algunos
casos, una excepcin generada en un mtodo debe especificarse como tal en una clu-
sula throw. El cdigo que deba ejecutarse tras salir de un bloque try se incluye en un
bloque f inally.
Preguntas al experto
P: Para estar seguro, puede repetir las condiciones que provocan una excepcin?
R: Las excepciones se generan de tres formas. Por un lado, la mquina virtual de
Java puede generar una excepcin en respuesta a un error interno que no pueda
controlar. Normalmente, su programa no controlar este tipo de excepciones. Por
otra parte, las excepciones estndar, como las de divisin por cero o superacin de
los lmites de una matriz, se generan por errores en el cdigo de su programa. Debe
controlar estas excepciones. Por ltimo, puede generar manualmente una excepcin
por medio de la instruccin throw. Independientemente de cmo se genere una
excepcin, se controla de la misma forma.
Utilizar try y catch
t ry y ca t ch forman la base del control de excepciones. Estas palabras clave funcionan
de forma conjunta; no puede usar catch sin try. Veamos el formato general de los
bloques de control de excepciones try / catch:
try {
11 bloque de cdigo para monitorizar errores
catch (TipoExcepl obExcep) {
11 controlador para TipoExcepl
catch (TipoExcep2 obExcep) {
11 controlador para TipoExcep2
Aqu, Ti poEx cep es el tipo de excepcin que se produce. Al generarse una excepcin,
se captura en su correspondiente instruccin catch, que la procesa. Como muestra el
formato general, puede haber ms de una instruccin ca tch asociada a una instruccin
try. El tipo de la excepcin determina qu instruccin catch ejecutar. Es decir, si el
tipo de excepcin especificado por una instruccin ca tch coincide con el de esa excep-
cin, se ejecuta la instruccin ca tch (y el resto se ignora). Al capturar una excepcin,
obExcep recibe su valor.
llfl 9. Controlar excepciones
Si no se genera una excepcin, el bloque try termina con normalidad y se ignoran
todas sus instrucciones c a tch. La ejecucin se reanuda en la primera instruccin tras
la ltima instruccin c a tch. Por tanto, las instrucciones c a tch slo se ejecutan si se
genera una excepcin.
Nota
JDK 7 aade una nueva forma de instruccin try que admite la administracin auto-
mtica de recursos y que se denomina try con recursos. La veremos en el captulo 10,
cuando describamos la gestin de flujos de E/ S (como los conectados a un archivo), ya
que los flujos son uno de los recursos ms utilizados.
Ejemplo de excepcin
El siguiente ejemplo muestra cmo buscar y capturar una excepcin. Como sabe, es
un error intentar indexar una matriz ms all de sus lmites. Si se produce, la MVJ genera
Ar rayi ndexOutOfBoundsException. El siguiente programa genera esta excepcin
deliberadamente y despus la captura:
11 Ejemplo de control de excepciones.
class ExcDemol {
public static void main(String args[])
int nums[] = new int[4];
try
System.out.println( " Before exception is generated.");
11 Generar una excepcin de ndice que supera los lmites .
nums[7] = 10;
System. out . println("this won ' t be displayed" ) ;
catch (ArrayindexOutOfBoundsException exc) {
11 capturar la excepcin
System.out.println("Index
System.out.println( " After catch statement ." ) ;
Este programa genera el siguiente resultado:
Befare exception is generated.
Index out- of-bounds!
After catch statement .
A pesar de su brevedad, el programa muestra distintos puntos clave sobre el control
de excepciones. Por un lado, el cdigo que permite monitorizar errores se incluye en un
bloque try. Por otra parte, al producirse una excepcin (en este caso por intentar indexar
Java 7 1111
nums ms all de sus lmites), la excepcin se genera fuera del bloque try y se captura
por c a tch. Tras ello, el control pasa a c a t c h y se termina el bloque try. Es decir, no se
invoca c a tch, sino que recibe la ejecucin del programa. Seguidamente, la instruccin
p r intln () que aparece tras el ndice nunca se ejecuta. Tras la ejecucin de c a tch, el
control del programa contina con las instrucciones que aparecen despus de c a t ch.
Por tanto, el controlador de excepciones debe solucionar el problema que provoca la
excepcin para que la ejecucin del programa pueda seguir con normalidad.
Recuerde que si un bloque try no genera una excepcin, no se ejecutan instrucciones
ca tch y el control del programa se reanuda tras la instruccin c a tch. Para confirmarlo,
en el programa anterior, cambie la lnea
nums[7] = 10 ;
por
nums[O] = 10 ;
Ahora no se genera la excepcin y el bloque c atch no se ejecuta.
Es importante entender que en el cdigo de un bloque try se controla la presencia
de excepciones, incluidas las que puedan generarse por un mtodo invocado desde un
bloque t r y. En ese caso, pueden capturarlas las instrucciones c a tch asociadas a ese
bloque try, siempre que el mtodo no haya capturado la excepcin por su cuenta. Por
ejemplo:
/ * Una excepcin se puede generar por un
mtodo y capturarse por otro. */
class ExcTest {
11 Generar una excepcin .
static void genException()
int nums[] = new int[4] ;
System. out . println( " Before exception is generated. " ) ;
//generar una excepcin de ndice que supera los lmites
nums[7] = 10;
System.out . println( " this won ' t be displayed" );
class ExcDemo2 {
public static void main(String args[]) {
try {
ExcTest . genException();
catch (ArrayindexOutOfBoundsException exc) {
11 capturar la excepcin
System.out . println( " Index out- of- bounds! " );
System. out . println( "After catch statement ." ) ;
IJll 9. Controlar excepciones
Este programa genera el siguiente resultado, el mismo que la primera versin del
programa:
Before exception is generated.
Index out-of-bounds!
After catch statement.
Como genException () se invoca desde un bloque try, la excepcin que genera (yno
captura) se captura por la instruccin ca tch de main(). Recuerde que si genException ()
hubiera capturado la excepcin, nunca la habra devuelto a rnain ().
Consecuencias de una excepcin sin capturar
La captura de una excepcin estndar de Java, como en el programa anterior, tiene
una ventaja adicional: evita que el programa termine de forma anmala. Al generarse
una excepcin, debe capturarse mediante cdigo, en alguna parte. Por lo general, si el
programa no la captura, lo hace la MVJ. El problema es que el controlador de excep-
ciones predeterminado de la MVJ termina la ejecucin y muestra una huella de pila y
un mensaje de error. Por ejemplo, en esta versin del ejemplo anterior, el programa no
captura la excepcin:
11 Dejar que la MVJ controle el error .
class NotHandled {
public static void main(String args[])
int nums[] = new int[4];
System.out.println( " Before exception is generated. ");
11 generar una excepcin de ndice que supera los lmites
nums[7] = 10;
Cuando se produce el error de ndice de matriz, la ejecucin se detiene y se muestra
el siguiente mensaje de error:
Exception in thread " main'' java.lang. ArrayindexOutOfBoundsException: 7
at NotHandled . main(NotHandled . java:9)
Aunque es un mensaje til para tareas de depuracin, no conviene que otros lo vean.
Por este motivo es importante que su programa controle las excepciones y no depender
de la MVJ.
Como mencionamos antes, el tipo de excepcin debe coincidir con el tipo especificado
en la instruccin ca tch. En caso contrario, la excepcin no se captura. Por ejemplo, el
siguiente programa intenta capturar un error de lmites de matriz con una instruccin
catch paraAri thrneticException (otra de las excepciones integradas de Java). Cuando
se supera el lmite de la matriz, se genera ArrayindexOutOfBoundsException pero la
instruccin ca tch no la captura, lo que provoca la finalizacin anmala del programa.
No funcionar!
=:ass ExcTypeMismatch
public static void main(String args[]) {
int nums[) = new int[4) ;
try
System.out . println( " Before exception is generated.");
// generar una excepcin de indice que supera los lmites
nums (7) = 10 ;
System.out.println( " this won ' t be displayed" ) ;
/* No se puede capturar un error de lmite de matriz
con ArithmeticException . */
catch (ArithmeticException exc) {
// capturar la excepcin
System. out .println( "Index out- of-bounds !");
System.out . println("After catch statement. " );
Este programa genera el siguiente resultado:
Before exception is generated.
Exception in thread "main" java.lang.ArraylndexOutOfBoundsException: 7
at ExcTypeMismatch.main(ExcTypeMismatch . java :l O)
Java 7 11,j
Como puede ver, la instruccin catch de Ari thmeticException no captura
ArrayindexOutOfBoundsException.
Excepciones para controlar errores con elegancia
Una de las ventajas del control de excepciones es que le permite programar como
respuesta a un error y despus proseguir la ejecucin. El siguiente ejemplo divide los
elementos de una matriz por los de otra. Si se produce una divisin por cero, se genera
Ari thmeticException. En el programa, esta excepcin se controla informando del
error y retomando la ejecucin. Por ello, el intento de divisin por cero no genera un
brusco error de tiempo de ejecucin que finalice el programa. En su lugar, se procesa de
forma elegante y permite que prosiga la ejecucin del programa.
11 Controlar el error con elegancia y continuar .
class ExcDemo3 {
public static void main (String args [ J) {
int numer[) { 4, 8, 16, 32, 64 , 128 };
int denom [) = { 2, O, 4, 4, O, 8 } ;
for(int i=O; i<numer.length; i++)
try {
System.out.println(numer[i) + " / " + denom[i) +" is " +
numer[i]/denom[i]) ;
1111 9. Controlar excepciones
catch (ArithmeticException exc) {
// capturar la excepcin
System. out . println( "Can ' t divide by Zero! " ) ;
Este programa genera el resultado mostrado en la figura 9.1.
Figura 9.1. Resultado generado por el programa ExcDemo3.
En el ejemplo, cuando se procesa una excepcin, se elimina del sistema. Por ello,
en el programa, en cada iteracin del bucle se entra en un bloque try nuevo; todas
las excepciones anteriores se controlan. Esto permite al programa controlar los errores
repetidos.
Utilizar varias instrucciones catch
Como mencionamos antes, puede asociar ms de una instruccin c a t ch a una instruc-
cin try. De hecho, es lo habitual. Sin embargo, cada instruccin catch debe capturar
un tipo de excepcin diferente. Por ejemplo, el siguiente programa captura errores de
lmite de matrices y divisin por cero:
// Usar varias instrucciones catch .
class ExcDemo4 {
public static void main(String args[])
11 Aqu , numeres mayor que denom.
nt numer [] 4 , 8 , 16, 32 , 64 , 128 , 256 , 512 };
int denom[] = { 2 , O, 4, 4 , O, 8 };
for(int i=O; i<numer . length; i++)
try {
System. out . println(numer[i] + " / " + denom[i] + " is " +
numer[i]/denom[i]) ;
catch (ArithmeticException exc) { // varias instrucciones catch
// capturar la excepcin
System. out . println( " Can ' t divide by Zero! ");
catch (ArrayindexOutOfBoundsException exc) {
Java 7 llfl
// capturar la excepcin
System. out . println( " No matching element found .");
En la figura 9 .2 puede ver el resultado generado por este cdigo.
ii Simbolo del iistema
Figura 9.2. Ejemplo de uso de varias instrucciones catch.
Como confirma el resultado, cada instruccin ca tch slo responde a su propio tipo
de excepcin. Por lo general, las expresiones catch se comprueban en el orden en que
aparecen en el programa. Slo se ejecuta la instruccin que coincida y los dems bloques
c atch se ignoran.
Capturar excepciones de subclases
Existe un factor importante sobre la presencia de varias instrucciones ca tch que
se relaciona con las subclases. Una clusula catch de una superclase tambin debe
coincidir con sus subclases. Por ejemplo, como la superclase de todas las excepciones
es Throwable, para capturar todas las excepciones posibles, capture Throwabl e. Si
desea capturar excepciones de superclase y subclases, incluya primero la superclase en
la secuencia ca tch. En caso contrario, la instruccin ca tch de superclase tambin captu-
rar todas las clases derivadas. Esta regla es de aplicacin automtica ya que al incluir
primero la superclase se crea cdigo inaccesible, ya que la clusula c a tch de subclase
nunca se podr ejecutar. En Java, el cdigo inaccesible es un error.
Fjese en el siguiente programa:
/ / Las subclases deben aparecer antes que las superclases en instrucciones catc h .
class ExcDemo5 {
public static void main(String args[])
//Aqu , numeres mayor que denom.
int numer[ ] = { 4, 8 , 16 , 32 , 64 , 128 , 256 , 512 };
int denom[] = { 2 , O, 4 , 4 , O, 8 };
for(int i =O; i <numer . length; i++) {
try {
System. out . println(numer[i] + " / " + denom[i] + '' is " +
numer[i]/denom[i]) ;
111:1 9. Controlar excepciones
catch (ArrayindexOutOfBoundsException exc) { // capturar subclase
11 capturar la excepcin
System. out . println( " No matching element found. " );
catch (Throwable exc) { // capturar superclase
System. out . println( " Some exception occurred. " );
Este programa genera el resultado mostrado en la figura 9.3.
Figura 9.3. Resultado tras ejecutar el programa ExcDemoS.
En este caso, ca tch ( Throwable) captura todas las excepciones menos Arra y
IndexOu tOfBoundsException. La captura de excepciones de subclase es ms impor-
tante cuando cree sus propias excepciones.
Preguntas al experto
.
P: Para qu sirve la captura de excepciones de superclase?
R: Existen varios motivos. Por un lado, si aade una clusula catch que capture
excepciones de tipo Exception, habr incluido una clusula de captura global que
afecte a todas las excepciones relacionadas con el programa. Dicha clusula puede
ser til en casos en los que deba evitar la terminacin anmala del programa inde-
pendientemente de lo que suceda. Por otra lado, en determinados casos, se puede
controlar una categora completa de excepciones por medio de la misma clusula.
Al capturar la superclase de estas excepciones puede controlar todo sin cdigo
duplicado.
Anidar bloques try
Un bloque try se puede anidar dentro de otro. Una excepcin generada en el bloque
try interno que no se capture con la instruccin ca tch asociada a dicho bloque se propaga
al bloque try externo. Por ejemplo, en este caso ArrayindexOutOfBoundsException
no se captura en la clusula catch interna pero s en la externa:
Usar un bloque try anidado
~ l s s NestTrys {
public static void main(String args(]) {
11 Aqu , numeres mayor que denom.
in t n ume r [ ] { 4 , 8 , 1 6 , 3 2 , 6 4 , 12 8 , 2 5 6 , 512 ) ;
int denom[] = { 2 , O, 4 , 4 , O, 8 ) ;
try { // try externo
for (int i=O; i<numer . length; i++)
try { // try anidado
System. out . println(numer[i] + '' / " + denom[i] + " is " +
numer[i]/denom[i]) ;
catch (ArithmeticException exc) {
11 capturar la excepcin
System. out.println( " Can ' t divide by Zero! " ) ;
catch (ArrayindexOutOfBoundsException exc)
// capturar la excepcin
System. out . println( " No matching element found ." );
System. out . println( " Fatal error -- program terminated." );
En la figura 9.4 puede ver el resultado generado por este programa.
Figura 9.4. Ejemplo de bloques try anidados.
Java 7 lliji
En este ejemplo, una excepcin que se puede controlar en el bloque t ry interno, en
este caso un error de divisin por cero, permite al programa continuar. Sin embargo, el
bloque try externo captura un error de lmite de matriz, lo que hace que el programa
termine.
Aunque no sea la nica funcin de las instrucciones try anidadas, el programa ante-
rior demuestra un hecho importante que se puede generalizar. A menudo, los bloques
try anidados se usan para que distintas categoras de errores se puedan controlar de
distinta forma. Algunos tipos de errores son catastrficos y no se pueden solucionar.
Otros son menores y se pueden resolver inmediatamente. Muchos programadores usan
un bloque try externo para capturar los errores ms graves y los bloques try internos
para controlar los menos serios.
lt.:.111 9. Controlar excepciones
Generar una excepcin
En los ejemplos anteriores se capturaban las excepciones generadas automticamente
por la MVJ. Sin embargo, se puede generar una excepcin por medio de la instruccin
throw. Su formato general es el siguiente:
throw objetoExcep;
obj etoExcep debe ser un objeto de una clase de excepcin derivada de
Throwable.
El siguiente ejemplo ilustra la instruccin throw generando Ari thmeticException
de forma manual:
11 Generar manualmente una excepcin .
class ThrowDemo {
public static void main(String args[)) {
try {
System. out.println( " Before throw.");
throw new ArithmeticException(); //generar la excepcin
catch (ArithmeticException exc) {
// capturar la excepcin
System. out.println( " Exception caught .");
System. out . println( "After try/catch block. " );
Este programa genera el siguiente resultado:
Before throw.
Exception caught.
After try/catch block.
Se crea Ari thmeticException por medio de newenlainstruccin throw. Recuerde
que throw genera un objeto, por lo que debe crear un objeto para que lo genere. Es decir,
no basta con generar un tipo.
Preguntas al experto
P: lPara qu querra generar una excepcin manualmente?
R: En muchos casos, las excepciones que genere sern instancias de las clases de ex-
cepcin que haya creado. Como veremos ms adelante, al crear sus propias clases de
excepcin puede procesar errores de su cdigo como parte de la estrategia general
de control de excepciones de su programa.
Java 7 ltJI
Volver a generar una excepcin
Una excepcin capturada por una instruccin ca tch se puede volver a generar hasta
que la capture una instruccin ca tch externa. De este modo, varios controladores pueden
acceder a la excepcin. Por ejemplo, puede que un controlador de excepciones gestione
un aspecto de una excepcin y otro se encargue de otro aspecto. Recuerde que al volver
a generar una excepcin, no se vuelve a capturar en la misma instruccin catch, sino
que se propaga a la siguiente.
El siguiente programa ilustra este proceso:
//Volver a generar una exce pcin .
class Rethrow {
public static void genException( )
// aqu , numeres mayor que denom
in t n ume r [ ] { 4 , 8 , 16, 3 2 , 6 4 , 12 8 , 2 5 6 , 512 } ;
int denom[] = { 2 , O, 4, 4, O, 8 };
for(int i=O; i<numer.length; i++)
try {
System. out . println(numer[i) + " / " + denom[ i ) + " is " +
numer[i)/denom[i]);
catch (ArithmeticException e xc) {
11 capturar la excepcin
System. out . println( " Can ' t divide by Zero! " );
catch (ArrayindexOutOfBoundsException exc)
// capturar la excepcin
System. out . println( " No matching element found ." );
throw exc ; // volver a generar la excepcin
class RethrowDemo {
public static void main(String args[]) {
try {
Rethrow. genException();
catch(ArrayindexOutOfBoundsExcepti on exc) {
// volver a capturar la excepcin
System.out . println( " Fatal error -- " + "program terminated." ) ;
}
En este programa, los errores de divisin por cero se controlan de forma local por
medio de genException (),pero se vuelve a generar un error de lmite de matriz que,
en este caso, se captura en rnain ().
lfjl 9. Controlar excepciones
Anlisis de Throwable
Hasta el momento, hemos capturado excepciones pero no hemos hecho nada con el
propio objeto de excepcin. Como se demuestra en los ejemplos anteriores, una clusula
catch especifica un tipo de excepcin y un parmetro. El parmetro recibe el objeto
de excepcin. Como todas las excepciones son subclases de Throwable, todas admiten
los mtodos definidos por Throwable. En la tabla 9.1 se muestran algunos de los ms
utilizados.
Tabla 9.1. Mtodos ms utilizados definidos por Throwable.
Mtodo Descripcin
Throwable fillinStackTrace ()
String getLocalizedMessage ()
String getMessage ()
void printStackTrace ()
Devuelve un objeto Throwable que
contiene un rastreo de pila completo. Este
objeto se puede volver a generar.
Devuelve una descripcin localizada de la
excepcin.
Devuelve una descripcin de la excep-
cin.
Muestra el rastreo de pila.
void printStackTrace (PrintStream flujo) Enva el rastreo de pila al flujo especifi-
cado.
void printStackTrace (PrintWriter flujo) Enva el rastreo de pila al flujo especifi-
cado.
String toString () Devuelve un objeto String que contiene
una descripcin completa de la excepcin.
Este mtodo se invoca por println () al
representar un objeto Throwable.
De los mtodos definidos por Throwable, dos de los ms interesantes son
printStackTrace () y toString () .Puede mostrar el mensaje de error estndar ms
un registro de las invocaciones de mtodos que han propiciado la excepcin si invoca
printStackTrace (). Puede usar toString () para recuperar el mensaje de error
estndar. Este mtodo tambin se invoca cuando se usa una excepcin como argumento
de println ( ).El siguiente programa demuestra estos mtodos:
11 Utilizar los mtodos de Throwable .
class ExcTest {
static void genException()
int nums(] = new int(4];
System.out.println( " Before exception is generated.");
11 generar una excepcin de ndice que supera los lmites
nums[7] = 10 ;
System. out . println( " this won ' t be displayed" );
class UseThrowableMethods {
public static void main(String args[)) {
try {
ExcTest . genException() ;
catch (ArraylndexOutOfBour.dsException exc) {
11 capturar la excepcin
System. out . println( " Standard message is : " ) ;
System. out . println(exc) ;
System.out . println( " \nStack trace : " ) ;
exc.printStackTrace() ;
System. out . println( " After catch statement .");
Este programa genera el resultado mostrado en la figura 9.5.
Figura 9.5. Resultado generado por el programa ExcTest.
Utilizar finally
Java 7 lfJI
En ocasiones tendr que definir un bloque de cdigo que se ejecute al salir de un
bloque try / catch. Por ejemplo, una excepcin puede provocar un error que termine
el mtodo actual de forma prematura. Sin embargo, ese mtodo puede haber abierto un
archivo o una conexin de red que haya que cerrar. Son casos habituales en programa-
cin y Java los soluciona por medio de f ina lly.
Para especificar un bloque de cdigo que ejecutar al salir de un bloque t ry / c at c h,
incluya un bloque f i nal l y al final de la secuencia try / c atch. El formato general de
un bloque try/ catch con final l y es el siguiente:
try {
11 bloque de c digo para errores
ti
9. Controlar excepciones
catch (TipoExcepl obExcep) {
11 controlador para TipoExcepl
catch (TipoExcep2 obExcep) {
11 controlador para TipoExcep2
}
/ / ...
finally
11 cdigo de finally
El bloque finally se ejecuta siempre que la ejecucin salga de un bloque try/
ca tch, independientemente de las condiciones que lo provoquen. Es decir, indepen-
dientemente de que el bloque try finalice con normalidad o debido a una excepcin, el
ltimo cdigo que se ejecuta es el definido por finally. El bloque finally tambin
se ejecuta si dentro del bloque try o de sus instrucciones ca tch hay cdigo que se
devuelva del mtodo.
Veamos un ejemplo de finally:
11 Usar finally .
class UseFinally
public static void genException(int what) {
int t;
int nums[] = new int[2];
System.out.println( " Receiving " + what);
try {
switch(what)
case O:
t = 10 / what; // generar error de divisin por cero
break;
case 1:
nums[4]
break;
case 2 :
4 ; // generar error de ndice de matriz.
return; // resultado del bloque try
catch (ArithmeticException exc) {
// capturar la excepcin
System.out . println("Can't divide by Zero!");
return; // resultado de catch
catch (ArrayindexOutOfBoundsException exc)
// capturar la excepcin
System.out . println( "No matching element found ." );
finally { // se ejecuta al salir de bloques try/catch
System.out.println( " Leaving try. " );
class FinallyDemo {
public static void main(String args[)) {
for (int i=O; i < 3 ; i++) {
UseFinally . genException(i);
System. out . println();
En la figura 9.6 puede ver el resultado.
Figura 9.6. Ejemplo de uso de finally.
/aval lf.Jej
Corno indica el resultado, independientemente de cmo se salga del bloque try, el
bloque f inally se ejecuta.
Utilizar throws
En algunos casos, si un mtodo genera una excepcin que no controla, debe declarar
dicha excepcin en una clusula throws. El formato general de un mtodo con una
clusula throws es el siguiente:
tipo- dev nombreMetodo(lista-param) throws lista- excep {
11 cuerpo
Aqu, lista-excep es una lista separada por comas de excepciones que el mtodo
puede generar fuera de s mismo.
Se preguntar por qu no hemos especificado una clusula throws en algunos de los
ejemplos anteriores, que generaban excepciones fuera de mtodos. La respuesta es que
no es necesario que las excepciones que son subclases de Error o RuntirneException
se especifiquen en una lista throws. Java simplemente asume que un mtodo puede
generar una. Los dems tipos de excepciones deben declararse. En caso contrario se
genera un error de compilacin.
En realidad, vimos un ejemplo de clusula throws en un apartado anterior ..
recuerda, al realizar entradas desde el teclado, tuvimos que aadir la clusula
,
throws java. io. IOException Q

=---
lfll 9. Controlar excepciones
a mai n (). Ahora entender el motivo. Una instruccin de entrada puede generar
I OExcept i on y, en aquel momento, no podamos controlarla. Por tanto, dicha excep-
cin se generara fuera de main () y tendra que especificarse como tal. Ahora que tiene
conocimientos sobre excepciones, puede controlar IOException con facilidad.
Veamos un ejemplo que controla IOException. Crea el mtodo prompt ( ) que
muestra un mensaje y despus lee un carcter del teclado. Como se realiza una entrada,
puede generarse IOException. Sin embargo, el mtodo prompt () no la controla, sino
que usa una clusula throws , lo que significa que el mtodo invocador debe controlarla.
En este ejemplo, el mtodo invocador es main ( ) y se encarga del error.
11 Usar throws.
class ThrowsDemo {
public static char prompt(String str)
throws java . io.IOException { //clusula throws
System. out.print(str + ": " ) ;
return (char) System. in.read() ;
public static void main(String args[)) {
char ch;
try {
ch prompt( "Enter a letter" ); //como prompt() puede generar una
11 excepcin su invocacin debe incluirse en
11 un bloque try
catch(java.io . IOException exc) {
System. out . println( " I/O exception occurred. " ) ;
ch = ' X' ;
System. out.println (" You pressed " +ch);
Comprobar que IOExce ption est totalmente cualificado por el nombre de su
paquete, java . io. Como veremos en el siguiente captulo, el sistema E/ S de Java
se incluye en el paquete java . io, por lo que tambin se incluye IOException.
Tambin podramos haber importado j a va . i o y hacer referencia directamente a
IOException.
Nuevas funciones de excepciones de JDK 7
Con el lanzamiento del JDK 7, el mecanismo de control de excepciones de Java se
ha ampliado considerablemente con la inclusin de tres novedades. La primera admite
la gestin automtica de recursos, que automatiza el proceso de liberacin de recursos,
como archivos, cuando dejan de ser necesarios. Se basa en una forma ampliada de try,
Java 7 lfll
denominada instruccin try con recursos y se describe en el captulo 10, cuando veamos
los archivos. La segunda novedad se denomina captura mltiple y la tercera, regenera-
cin final o regeneracin ms precisa, como se describe a continuacin.
La captura mltiple permite que una misma clusula ca tch capture dos o ms excep-
ciones. Como vimos antes, es posible, y habitual, que una instruccin try est seguida de
dos o ms clusulas ca tch. Aunque cada clusula ca tch suele proporcionar su propia
secuencia exclusiva de cdigo, es habitual que dos o ms clusulas ca tch ejecuten la
misma secuencia de cdigo aunque capturen excepciones diferentes. En lugar de tener
que capturar cada tipo de excepcin de forma individual, puede usar una misma clu-
sula ca tch para controlar la excepcin sin duplicar el cdigo.
Para crear una captura mltiple, debe especificar una lista de excepciones en una misma
clusula ca tch. Para ello debe separar los tipos de excepcin de la lista con el operador
OR. Cada parmetro es final de forma implcita. (Puede especificar final de forma
explcita si lo desea, pero no es necesario.) Por ello, no se pueden asignar nuevos valores
a estos parmetros. A continuacin se muestra cmo usar la funcin de captura mltiple
para capturar Ar i thrneticException y Array indexOutOfBoundsException con
una misma clusula ca t c h:
catch(final ArithmeticException 1 ArrayindexOutOfBoundsException e) {
El siguiente programa ilustra el uso de la captura mltiple:
/ / Usar la funcin de captura mltiple. Nota : Este cdigo requiere JDK 7 o
/ / posterior para su compilacin .
class MultiCatch {
public static void main(String args[J) {
int a=BB , b=O;
int result ;
char chrs [] = { ' A' , ' B' , ' C' ) ;
for (int i=O; i < 2 ; i++) {
try {
if (i == 0)
result =a / b ; //generar ArithmeticException
el se
chrs[SJ = ' X'; //generar ArrayindexOutOfBoundsException
//Esta clusula catch captura las dos excepciones .
catch(ArithmeticException 1
ArrayindexOutOfBoundsException e) {
System.out . println( "Exception caught: " + e);
System.out.println( " After
El programa genera Ari thrnet icExcept ion al intentar la divisin por cero y genera
ArrayindexOutOfBoundsExce ption al intentar el acceso fuera de los lmites de chrs.
Ambas excepciones se capturan en la misma clusula ca tch.
lf..1:1 9. Controlar excepciones
La funcin de regeneracin ms precisa limita el tipo de excepciones que regenerar a
las excepciones comprobadas que un bloque try asociado genera, que no se controlan
por una clusula ca tch anterior y que son un subtipo o supertipo del parmetro. Aunque
puede que esta funcin no sea necesaria, est disponible. Para aplicarla, el parmetro
ca tch debe ser fina 1, lo que significa que no se le puede asignar un nuevo valor dentro
del bloque catch. Tambin se puede especificar explcitamente como final aunque
no es necesario.
Excepciones integradas de Java
Dentro del paquete estndar java. lang, Java define varias clases de excepcin.
Hemos usado algunas en los ejemplos anteriores. Las ms generales son subclases del
tipo estndar RuntimeException. Como java. lang se importa explcitamente a todos
los programa de Java, no es necesario incluirlas en la lista throws de ningn mtodo.
En Java, se denominan excepciones sin comprobar ya que el compilador no comprueba
si un mtodo las controla o las genera. Las excepciones sin comprobar definidas en
java . lang se resumen en la tabla 9.2. La tabla 9.3 enumera las excepciones definidas
por java . lang que deben incluirse en la lista throws de un mtodo si dicho mtodo
puede generar una de ellas y no la controla personalmente. Se denominan excepciones
comprobadas. Java define otros tipos de excepciones relacionadas con sus bibliotecas de
clases, como IOException que mencionamos antes.
Tabla 9.2. Excepciones sin comprobar definidas en java.lang.
Excepcin
ArithmeticException
Significado
Error aritmtico, como un entero dividido por
cero.
ArrayindexOutOfBoundsException El ndice de la matriz supera sus lmites.
ArrayStoreException Asignacin de un elemento de matriz de un tipo
incompatible.
ClassCastException Conversin invlida.
EnumConstantNotPresentException Se intenta usar un valor de enumeracin sin
definir.
IllegalArgumentException Argumento ilegal usado para invocar un m-
todo.
IllegalMoni torSta teException Operacin de monitor ilegal, como por ejemplo la
espera en un subproceso desbloqueado.
IllegalStateException El estado del entorno o la aplicacin es inco-
rrecto.
Illegal ThreadStateException La operacin solicitada no es compatible con el
estado del subproceso actual.
Excepcin
IndexOutOfBoundsException
NegativeAr raySizeException
NullPointerException
NurnberForrnatException
Java 7 lfJI
Significado
Algn tipo de ndice supera los lmites.
Matriz creada con un tamao negativo.
Uso incorrecto de una referencia null.
Conversin incorrecta de una cadena a un formato
numrico.
Securi tyException Intento de violacin de seguridad.
StringindexOutOfBoundsException Intento de indexar fuera de los lmites de una
cadena.
TypeNotPresentException
Unsupporte dOperationException
Tipo no encontrado.
Se ha detectado una operacin no admitida.
Tabla 9.3. Excepciones comprobadas definidas en java.lang.
Excepcin
ClassNot FoundException
CloneNotSupportedException
Il l egalAccessException
InstantiationException
InterruptedException
NoSuchFieldException
NoSuchMethodException
ReflectiveOperationException
Preguntas al experto
Significado
Clase no encontrada.
Intento de clonar un objeto que no implementa la
interfaz Cloneable.
Acceso denegado a una clase.
Intento de crear un objeto de una clase o interfaz
abstracta.
Un subproceso ha interrumpido otro.
No existe el campo solicitado.
No existe el mtodo solicitado.
Superclase de excepciones relacionadas con la
reflexin (novedad de JDK 7).
P: He odo que Java admite las denominadas excepciones encadenadas. ne qu se
trata?
R: Las excepciones encadenadas se aadieron en el JDK i.4. Le permiten especificar
una excepcin corno causa subyacente de otra. Por ejemplo, imagine que un mtodo
genera Ari thrneticException debido a un intento de divisin por cero. Sin ern-
11111 9. Controlar excepciones
bargo, la causa real del problema es un error de E/S, que hace que el divisor se esta-
blezca incorrectamente. Aunque el mtodo debe generar Ari thrneticExc eption,
por ser el error causado, puede que desee que el cdigo invocador sepa que la causa
subyacente es un error de E/S. Las excepciones encadenadas le permiten solucionar
situaciones en las que existen niveles de excepciones.
Para permitir excepciones encadenadas, se aaden dos constructores y dos mtodos
a Th rowa b le. Los constructores son los siguientes:
Throwable(Throwable causaExcep)
Throwable (String mensaje , Throwable causaExcep)
En el primero, causaExcep es la excepcin responsable de la excepcin actual, es
decir, el motivo subyacente de la excepcin. En el segundo, puede especificar una
descripcin al mismo tiempo que una causa de excepcin. Estos dos constructores
tambin se aadieron a las clases Error, Except i on y RuntirneException.
Los mtodos de excepciones encadenadas aadidos a Throwa ble son ge tCause ( )
e ini tCause (),como se muestra a continuacin:
Throwable getCause( )
Throwable initCause(Throwable causaExcep)
El mtodo getCause () devuelve la excepcin que subyace a la actual. Si no existe
una excepcin subyacente, se devuelve null. El mtodo ini t Cause () asocia
causaExcep a la excepcin invocadora y devuelve una referencia a la excepcin.
Por tanto, puede asociar una causa a una excepcin despus de que se haya creado
la excepcin. Por lo general, ini tea use ( ) se usa para establecer una causa para
clases de excepcin de legado que no admiten los dos constructores adicionales
descritos antes.
Las excepciones encadenadas no son necesarias en todos los programas pero en casos
en los que conviene saber la causa subyacente, ofrecen una elegante solucin.
Crear subclases de excepcin
Aunque las excepciones integradas de Java controlan los errores ms habituales, el
mecanismo de control de excepciones no se limita a estos. De hecho, parte de la potencia
de este enfoque radica en la capacidad para controlar excepciones que cree y que se corres-
pondan a errores de su propio cdigo. La creacin de una excepcin es muy sencilla.
Basta con definir una subclase de Exception (que es, evidentemente, una subclase de
Throwabl e ). No es necesario que las subclases implementen nada; su mera existencia
en el sistema de tipos le permite usarlas como excepciones.
La clase Exception no define mtodos propios. Pero hereda los de Throwable.
Por tanto, todas las excepciones, incluidas las que cree personalmente, disponen de los
mtodos definidos por Throwable. Evidentemente, puede reemplazar uno o varios de
estos mtodos si lo desea.
Java 7 1111
El siguiente ejemplo crea la excepcin NonintResul tException, que se genera
cuando el resultado de dividir dos valores enteros tiene un componente fraccional.
Nonint Resul tExceptio n tiene dos campos para almacenar los valores enteros: un
constructor y un reemplazo del mtodo toString (),lo que permite mostrar la descrip-
cin de la excepcin por medio de p r in t 1 n ( ) .
// Usar una excepcin personalizada.
//Crear una excepcin .
class NonintResultException extends Exception {
int n ;
int d ;
NonintResultException(int i , int j) {
n i ;
d = j ;
public String toString()
return " Result of " + n + " / " + d + " is non- integer .";
class CustomExceptDemo {
public static void main(String args[])
11 Aqu , numer contiene valores .
int numer[) = { 4 , 8 , 15 , 32 , 64 , 127, 256, 512 };
int denorn[) = { 2 , O, 4 , 4 , O, 8 };
for (int i=O; i<nurner. length; i++) {
try {
if ( ( n ume r [ i ] % 2) ! = O )
throw new
Noni ntResultException(nurner[i] , denom[i)) ;
System.out . println(numer[i) +
11
/ " + denorn[i] +
11
is " +
numer[i)/denom[i)) ;
catch (ArithmeticException exc) {
11 capturar la excepcin
System.out.println(
11
Can ' t divide by Zero!
11
) ;
catch (ArrayindexOutOfBoundsException exc)
11 capturar la excepcin
System.out.println (
11
No matching element found.
11
);
catch (NonintResultException exc) {
System.out.println(exc) ;
lltl 9. Controlar excepciones
La salida del programa se muestra a continuacin:
4 / 2 is 2
Can ' t divide by Zero!
Result of 15 / 4 is non-integer .
32 / 4 is 8
Can ' t divide by Zero!
Result of 127 / 8 is non- integer .
No matching element found.
No matching element found .
Preguntas al experto
P: cundo debo usar control de excepciones en un programa? cundo debo crear
mis propias clases de excepcin personalizadas?
R: Como el API de Java usa las excepciones para informar de errores, prcticamente
todos los programas del mundo real emplean el control de excepciones. Es la parte
del control de excepciones que los programadores noveles de Java encuentran
ms sencilla. Resulta ms complicado decidir cundo y cmo usar sus propias
excepciones. Por lo general, hay dos formas de informar sobre un error: devolver
valores y con excepciones. El mejor enfoque? Sinceramente, en Java, el control
de excepciones debera ser la norma. Es evidente que devolver un cdigo de error
es una alternativa vlida en algunos casos, pero las excepciones constituyen una
forma ms completa y estructurada de solucionar errores, y la que utilizan los
programadores profesionales de Java en su cdigo.
Ejercicio 9.1. Aadir excepciones a la clase Queue
En este ejercicio crearemos dos clases de excepcin que podremos usar en las clases
de cola desarrolladas en el ejercicio 8.1. Indicarn condiciones de error de cola llena y
de cola vaca. Estas excepciones se pueden generar por los mtodos put ( ) y get ()
respectivamente. Por motivos de simplicidad, el ejercicio aade las excepciones a la clase
FixedQueue pero puede incorporarlas a las dems clases del ejercicio 8.1.
l . Cree un archivo con el nombre QExcDerno . java.
2. En su interior, defina las siguientes excepciones:
/*
Ejercicio 9.1
Aadir control de excepciones a las clases de cola.
*/
// Una excepcion para errores de cola l lena .
class QueueFullException extends Exception {
int size;
QueueFullException(int s) { size s ; }
public String toString()
return " \nQueue is full . Maximum size is " + size;
//Una excepcion para errores de cola llena vaca .
class QueueEmptyException extends Exception
public String toString() {
return " \nQueue is empty. " ;
Java 7 1111
QueueFul lException se genera al intentar almacenar un elemento en una cola
ya llena. QueueEmptyExc epti on se genera al intentar eliminar un elemento de
una cola vaca.
3. Cambie la clase FixedQueue para que genere excepciones cuando se produzca
un error, como se indica a continuacin. Adalo a QExc Demo. jav a.
//Una clase de cola de tamao fijo para caracteres que usa excepciones.
class FixedQueue implements ICharQ {
prvate char q(] ; //esta matriz contiene la cola
prvate int putloc, getloc; // los ndices put y get
//Crear una cola vaca dado si tamao.
public FixedQueue(int size)
q = new char[size+l] ; //asignar memoria para la cola
putloc = getloc = O;
//Aadir un carcter a la cola .
public void put(char ch)
throws QueueFullException
if(putloc==q. length- 1)
throw new QueueFullException(q. length- 1);
putloc++;
q[putloc] ch;
//Obtener un carcter de la cola.
public char get()
throws QueueEmptyException
if(getloc == putloc)
throw new QueueEmptyException();
getloc++;
return q[getloc];
lit
9. Controlar excepciones
Se necesitan dos pasos para aadir excepciones a FixedQueue. Por un lado,
get () y put () deben incluir una clusula t h rows en sus declaraciones. Por otra
parte, cuando se produce un error, estos mtodos generan una excepcin. El uso
de excepciones permite al cdigo invocador controlar el error de forma racional.
Recordar que en versiones anteriores simplemente se informaba del error. La
generacin de una excepcin es un enfoque ms adecuado.
4. Para probar la clase FixedQueue actualizada, aada la siguiente clase QExcDemo
a QExcDemo . java:
11 Ejemplo de excepciones de cola .
class QExcDemo {
public static void main(String args[])
FixedQueue q = new FixedQueue(lO);
char ch;
int i ;
try {
11 desbordar la cola
f o r(i=O; i < 11 ; i++)
System. out .print( "Attempting to store
q . put((char) ( ' A' + i)) ;
System. out.println( " -- OK" );
System. out.println();
catch (QueueFullException exc)
System. out . println(exc) ;
System. out.println();
try {
11 sobre-vaciar la cola
for(i=O ; i < 11 ; i++) {
System.out . print( "Getting next char : " );
ch = q . get () ;
System. out . println(ch) ;
catch (QueueEmptyException exc)
System. out.println (exc) ;
"+ (char) ('A' + i));
5. Como FixedQueue implementa la interfaz ICharQ, que define los dos mtodos
de cola get () y put (),es necesario cambiar ICharQ para que refleje la clusula
t hrows. A continuacin se muestra la interfaz ICharQ actualizada. Recuerde
que debe incluirse en un archivo independiente con el nombre ICharQ. java.
11 Una interfaz de cola de caracteres que genera excepciones .
public interface ICharQ {
11 Aadir un carcter a la cola .
void put(char ch) throws QueueFullException;
11 Obtener un carcter de la cola.
char get() throws QueueEmptyException;
Java 7 IJiJ
6. Tras ello, compile el archivo I QCha r . j ava actualizado. Despus, compile
QExcDemo. java. Por ltimo, ejecute QExc Demo. Ver el resultado ilustrado en
la figura 9.7.
Figura 9.7. Resultado generado tras ejecutar QExcDemo.
Evaluacin de conocimientos
l. Qu clase se encuentra en la parte superior de la jerarqua de excepciones?
2. Explique brevemente el uso de t r y y ca tch.
3. Qu falla en el siguiente fragmento de cdigo?
11 ...
vals (18] = 10;
catch (ArrayindexOutOfBoundsException exc) {
11 controlar error
4. Qu sucede si no se captura una excepcin?
5. Qu falla en el siguiente fragmento de cdigo?
class A extends Exception { . . .
class B extends A { ...
11 ...
llUI 9. Controlar excepciones
try {
11
catch (A exc)
catch (B exc)
6. Una clusula catch interna puede volver a genera una excepcin en una clu-
sula e ate h externa?
7. El bloque finally es el ltimo fragmento de cdigo que se ejecuta antes de que
finalice un programa. Verdadero o falso? Justifique la respuesta.
8. Qu tipo de excepciones deben declararse de forma explcita en una clusula
throws de un mtodo?
9. Qu falla en el siguiente fragmento de cdigo?
class MyClass { // ...
11 ...
throw new MyClass ( );
10. En la pregunta 3 del apartado Evaluacin de conocimientos del captulo 6 creamos
una clase Stack. Aada excepciones personalizadas a esta clase que informen
cuando la pila est llena y vaca.
11. Qu tres formas existen de generar una excepcin?
12. Enumere dos subclases directas de Throwable.
13. Qu es la captura mltiple?
14. Su cdigo debe capturar excepciones de tipo Error?