Tutorial06 Excep
Tutorial06 Excep
Esto es difícil debido a que generalmente, el código que detecta el error no es el que puede
realizar dichas tareas. El que detecta el error debe informar al que pueda manejarlo.
La solución más habitual a esto son los códigos de error, es decir, que un método devuelva un
código de error como valor de retorno. Esto presenta una serie de inconvenientes:
En definitiva, hacen que el tratamiento de errores sea complejo y que, por ello, muchas veces
no se tenga en cuenta y no se traten todos los errores. Esto impide la construcción de
programas robustos.
Java ofrece una solución, otra forma de tratar con los errores: las excepciones.
En Java, cuando ocurre algo así, se lanza una excepción (throw) para que alguien que sepa
manejarla la trate en un contexto superior. Por ejemplo:
6-1
Laboratorio de Informática II - Excepciones
Con la palabra throw se lanza una excepción. Cuando ocurre esto, finaliza el método y se
lanza un objeto que facilite información sobre el error ocurrido. Normalmente se utilizará una
clase diferente para cada tipo de error.
Java obliga a que un método informe de las excepciones (explícitas) que puede lanzar. Un
método no sólo tienen que decir qué devuelve si todo va bien, también debe indicar qué
puede fallar. Un método especifica las excepciones que se pueden producir en él mediante la
palabra throws en la declaración del método. Por ejemplo:
void f() throws EOFException, FileNotFoundException
{
if( ... )
throw new EOFException();
if( ... )
throw new FileNotFoundException();
}
El try delimita el grupo de operaciones que pueden producir excepciones. El bloque catch es el
lugar al que se transfiere el control si alguna de las operaciones produce una excepción. Es
decir:
try{
// Operaciones que pueden “fallar”, es decir, que
// pueden producir alguna excepción.
}
catch( <tipoDeExcepción> ref ){
// Tratamiento de esa excepción
}
Por ejemplo:
try{
a.abreFichero();
a.leeCabecera();
a.actualizaDatos();
}
catch( IOException ref ){
System.out.println( “Error de E/S” );
}
6-2
Laboratorio de Informática II - Excepciones
Si alguna de las operaciones del bloque produce una excepción, se interrumpe el bloque try y
se ejecuta el catch. Al finalizar éste, se continúa normalmente. Si no se produce ninguna
excepción el bloque catch se ignora.
Un bloque try puede tener varios catch asociados, uno para cada tipo de excepción que se
pueda producir. Por ejemplo,
try{
a.abreFichero();
a.leeCabecera();
a.actualizaDatos();
}
catch( FileNotFoundException ref ){
System.out.println( “Error de apertura” );
}
catch( IOException ref ){
System.out.println( “Error de E/S” );
}
Si se produce una excepción que no se corresponde con ningún catch indicado, la excepción se
propaga hacia atrás en la secuencia de invocaciones hasta encontrar un catch adecuado. Por
ejemplo:
void f1( int accion ) throws EOFException
{
try{
if( accion == 1 )
throw new FileNotFoundException();
else if( accion == 2 )
throw new EOFException();
}
catch( FileNotFoundException e ){
System.out.println( “Error corregido” );
}
System.out.println( “Finalización normal de f1” );
}
6-3
Laboratorio de Informática II - Excepciones
Es decir, o se trata el error o se avisa que se va a continuar sin haberlo corregido para que
otro método lo corrija. Por ejemplo:
void f1() throws IOException
{
...
}
void f2()
{
try{
// Alternativa 1: tratar el error en cuanto se produce
f1()
}
catch( IOException e ){
// Tratamiento del error
}
}
Es mejor intentar tratar los errores en cuanto sea posible (alternativa 1), en vez de dejarlos
para que los gestione alguien por encima (alternativa 2). De todos modos, no siempre es
posible tratarlos en el mismo momento en que se producen y por tanto, a menudo hay que
recurrir a la segunda alternativa.
6.4.- FINALLY
Puede haber ocasiones en que se desea realizar alguna operación tanto si se producen
excepciones como si no. Dichas operaciones se pueden situar dentro de un bloque finally, de
la siguiente forma:
try{
// Operaciones con posibles excepciones
}
catch( <tipoDeExcepcion> ref ){
// Tratamiento de la excepción
}
finally{
// Operaciones comunes
}
6-4
Laboratorio de Informática II - Excepciones
Ejemplo:
class Recurso
{
void reserva(){ ... }
void libera(){ ... }
}
class Ejemplo
{
void prueba()
{
Recurso recurso = new Recurso();
try{
recurso.reserva();
// Operaciones con posibles excepciones
recurso.libera();
}
catch( ExceptionA a ){
// Tratamiento del error
recurso.libera();
}
catch( ExceptionB b ){
// Tratamiento del error
recurso.libera();
}
catch( ExceptionC c ){
// Tratamiento del error
recurso.libera();
}
}
}
6-5
Laboratorio de Informática II - Excepciones
catch( ExceptionC c ){
// Tratamiento del error
}
finally{
recurso.libera();
}
}
}
• Si es atrapada por un catch del mismo try, se ejecuta éste y luego el finally. La
ejecución continúa después del finally con normalidad.
La excepción pasaría a buscarse entre los catch de un contexto superior (los del mismo nivel se
ignoran).
• getMessage
• toString
• fillInStackTrace
• Throwable
6-6
Laboratorio de Informática II - Excepciones
• Error
• Exception
• RuntimeException
Todas las excepciones descienden de la clase Throwable, la cual se divide en dos subclases:
Error y Exception. Las clases derivadas de Error describen errores internos de la JVM e indican
errores serios que normalmente la aplicación no debería intentar gestionar. Tampoco deberían
ser lanzadas por las clases del usuario. Estas excepciones rara vez ocurren, y cuando así sea, lo
único que se puede hacer es intentar cerrar el programa sin perder datos. Ejemplos de este
tipo de excepciones son OutOfMemoryError, StackOverflowError, etc.
Los programas en Java trabajarán con las excepciones de la rama Exception. Esta clase, a su
vez, tiene una subclase llamada RuntimeException que, a su vez, tiene otras clases derivadas.
Estas excepciones se clasifican en:
6-7
Laboratorio de Informática II - Excepciones
El resto de las Exception indican que ha ocurrido algún error debido a alguna causa ajena al
programa (está correcto). Por ejemplo: un error de E/S, error de conexión, etc.
Los métodos deben declarar sólo las excepciones explícitas. Las implícitas no deben declararse
(el compilador no lo exige, aunque pueden producirse igualmente). Por tanto, cuando un
método declara una excepción, está avisando de que puede producirse dicho error (por causas
externas al método) además de cualquier error implícito (consecuencia de un error en el
código que debería ser subsanado).
En un método que tiene como parámetro un entero entre 1 y 12 se recibe un 14 ¿Qué tipo de
excepción se crearía para notificarlo?
Si un método para listar Clientes por impresora se encuentra con que deja de responder, ¿qué
tipo de excepción debería crear?
Cuando se produzca una excepción de este tipo, se lanzará, como se puede ver en el siguiente
ejemplo:
class Ejemplo
{
void imprimirClientes( Cliente[] clientes ) throws PrinterException
{
for( int i=0; i<clientes.length; i++ )
{
// Imprimir cliente[i]
if( “error impresión” ) throw new PrinterException();
}
}
}
6-8
Laboratorio de Informática II - Excepciones
Vemos ahora otro ejemplo en el que creamos y lanzamos una excepción de tipo
RuntimeException:
class MesInvalidoException extends RuntimeException
{}
class Ejemplo
{
void setMes( int mes )
{
if( mes < 1 || mes > 12 )
throw new MesInvalidoException();
}
}
En este ejemplo no se avisa que se lanza una excepción porque es de tipo RuntimeException
(implícita).
int getNumPagina()
{
return numPagina;
}
}
class Ejemplo
{
void imprimirClientes( Cliente[] clientes ) throws PrinterException
{
for( int pagina = 0; pagina<clientes.length; pagina++ )
{
// Imprimir cliente[ pagina ]
if( “error impresión” ) throw new PrinterException( pagina );
}
}
void Informe()
{
try{
imprimirClientes( clientes );
6-9
Laboratorio de Informática II - Excepciones
}
catch( PrinterException e )
{
System.out.println( “Sólo se han imprimido “ +
e.getNumPagina() );
}
}
}
MesInvalidoException( int m )
{
mes = m;
}
getMesInvalido()
{
return mes;
}
class Fecha
{
void setMes( int m )
{
if( m < 1 || m > 12 )
throw new MesInvalidoException( m );
}
}
class Ejemplo
{
public static void main( String[] args )
{
Fecha fecha = new Fecha();
fecha.setMes( 14 );
}
}
Java obliga a atrapar las excepciones explícitas, ¿qué pasa si no se atrapa una implícita, como
en este caso?
6-10
Laboratorio de Informática II - Excepciones
La clase Throwable tiene una serie de métodos que tienen ya implementados todas las
excepciones de Java (por herencia), y que pueden ser implementados por las nuevas
excepciones que se creen. Algunos de estos métodos son:
Lo mismo, pero pensado para devolver el mensaje localizado de una forma más
específica. Hay que redefinirlo, si no simplemente se comporta como getMessage()
Devuelve la representación String del error (la clase del error, básicamente).
Idem.
6-11
Laboratorio de Informática II - Excepciones
Excepciones implícitas:
• Derivan de RuntimeException.
• No se declaran: se corrigen.
class B extends A {
// Incorrecto
void f() throws EOFException, FileNotFoundException {}
}
Es decir, un hijo puede lanzar menos excepciones que las que declara el padre, no puede
lanzar una excepción que no lanzaba el padre, no puede lanzar nuevas excepciones.
Por otro lado, un método puede declarar excepciones que no lance realmente. Así un método
base puede permitir que las redefiniciones puedan producir excepciones.
6-12
Laboratorio de Informática II - Excepciones
Norma 2:
while (!stack.empty())
stack.pop();
Norma 3:
try {
for (int i = 0; i < len; i++) {
obj1.mesg1();
obj2.mesg2();
}
}
catch(ExcA a) {
// Tratamiento
}
catch(ExcB b) {
// Tratamiento
}
6-13
Laboratorio de Informática II - Excepciones
Norma 4:
6.12.- EJEMPLOS
6-14
Laboratorio de Informática II - Excepciones
if (posicion == 1)
l = new NodoLista( o, l );
else {
if (aux == null)
throw new FueraDeListaException("intentando insertar
elemento más allá del fin de la lista" );
else
aux.siguiente = new NodoLista( o, aux.siguiente );
}
}
6-15
Laboratorio de Informática II - Excepciones
try {
l.borrarPrimero();
} catch (FueraDeListaException e) {
System.out.println( "Error: " + e.getMessage() +
". Continuamos..." );
}
l.insertarPrimero( new Integer( 1 ) );
l.insertarPrimero( new Integer( 2 ) );
l.insertar( new Integer( 4 ), 1 );
l.insertar( new Integer( 3 ), 2 );
// no obligatorio recoger el error
// pq es RuntimeException
l.insertar( new Double( 2.5 ), 3 );
try {
l.insertar( new Integer( 18 ), 10 );
} catch (FueraDeListaException e) {
System.out.println( "Error: " + e.getMessage() +
". Continuamos..." );
}
finally {
l.insertarPrimero( new Integer(18) );
}
System.out.println( l );
l.destruir();
l.borrarPrimero();
// de este error no se recupera el programa
System.out.println( "Aquí no se llega... error en ejecución" );
}
}
Salida:
6.13.- EJERCICIOS
Escribe una clase llamada DividePorCero que pruebe a dividir un entero entre otro recogiendo
la excepción de división por cero y mostrando el mensaje "Error: división por cero" si se
produce.
6-16
Laboratorio de Informática II - Excepciones
Diseña e implementa una clase Fraccion que permite crear fracciones (numerador y
denominador enteros), con métodos para sumar, restar, multiplicar y dividirlas.
Crea una excepción FraccionException que se lance siempre que en una operación de fracción
se produzca un error, a saber:
Hacer que cada operación crítica lance esta excepción si se produce, con un mensaje indicativo
del tipo de error (mensaje incluido en la excepción, no salida a pantalla!). Probar la clase.
6-17