El trmino excepcin es un forma corta da la frase suceso excepcional y puede definirse de la siguiente forma.
Una excepcin es un evento que ocurre durante la ejecucin del programa que interrumpe el flujo normal de las sentencias.
Muchas clases de errores pueden utilizar excepciones desde serios problemas de hardware, como la avera de un disco duro, a los simples errores de programacin, como tratar de acceder a un elemento de un array fuera de sus lmites. Cuando dicho error ocurre dentro de un mtodo Java, el mtodo crea un objeto exception y lo maneja fuera, en el sistema de ejecucin. Este objeto contiene informacin sobre la excepcin, incluyendo su tipo y el estado del programa cuando ocurri el error. El sistema de ejecucin es el responsable de buscar algn cdigo para manejar el error. En terminologa java, crear una objeto exception y manejarlo por el sistema de ejecucin se llama lanzar una excepcin.
5.2 Tipos de excepciones
Existen varios tipos fundamentales de excepciones: Error: Excepciones que indican problemas muy graves, que suelen ser no recuperables y no deben casi nunca ser capturadas. Exception: Excepciones no definitivas, pero que se detectan fuera del tiempo de ejecucin. RuntimeException: Excepciones que se dan durante la ejecucin del programa.
Todas las excepciones tienen como clase base la clase Throwable, que est incluida en el paquete java.lang, y sus mtodos son:
Trowable( String mensaje ); Constructor. La cadena es opcional Throwable fillInStackTrace(); Llena la pila de traza de ejecucin. String getLocalizedMessage(); Crea una descripcin local de este objeto. String getMessage(); Devuelve la cadena de error del objeto. Void printStackTrace( PrintStream_o_PrintWriter s ); Imprime este objeto y su traza en el flujo del parmetro s, o en la salida estndar (por defecto). String toString; Devuelve una breve descripcin del objeto.
5.3 Propagacin de excepciones
La clusula catch comprueba los argumentos en el mismo orden en que aparezcan en el programa. Si hay alguno que coincida, se ejecuta el bloque y sigue el flujo de control por el bloque finally (si lo hay) y concluye el control de la excepcin.
Si ninguna de las clusulas catch coincide con la excepcin que se ha producido, entonces se ejecutar el cdigo de la clusula finally (en caso de que la haya). Lo que ocurre en este caso, es exactamente lo mismo que si la sentencia que lanza la excepcin no se encontrase encerrada en el bloque try. El flujo de control abandona este mtodo y retorna prematuramente al mtodo que lo llam. Si la llamada estaba dentro del mbito de una sentencia try, entonces se vuelve a intentar el control de la excepcin, y as continuamente.
Cuando una excepcin no es tratada en la rutina en donde se produce, lo que sucede es lo siguiente. El sistema Java busca un bloque try..catch ms all de la llamada, pero dentro del mtodo que lo trajo aqu. Si la excepcin se propaga de todas formas hasta lo alto de la pila de llamadas sin encontrar un controlador especfico para la excepcin, entonces la ejecucin se detendr dando un mensaje. Es decir, podemos suponer que Java nos est proporcionando un bloque catch por defecto, que imprime un mensaje de error, indica las ltimas entradas en la pila de llamadas y sale.
No hay ninguna sobrecarga en el sistema por incorporar sentencias try al cdigo. La sobrecarga se produce cuando se genera la excepcin.
Se ha indicado ya que un mtodo debe capturar las excepciones que genera, o en todo caso, declararlas como parte de su llamada, indicando a todo el mundo que es capaz de generar excepciones. Esto debe ser as para que cualquiera que escriba una llamada a ese mtodo est avisado de que le puede llegar una excepcin, en lugar del valor de retorno normal. Esto permite al programador que llama a ese mtodo, elegir entre controlar la excepcin o propagarla hacia arriba en la pila de llamadas. La siguiente lnea de cdigo muestra la forma general en que un mtodo declara excepciones que se pueden propagar fuera de l, tal como se ha visto a la hora de tratar la sentencia throws:
tipo_de_retorno( parametros ) throws e1,e2,e3 { } Los nombres e1,e2,... deben ser nombres de excepciones, es decir, cualquier tipo que sea asignable al tipo predefinido Throwable. Observar que, como en la llamada al mtodo se especifica el tipo de retorno, se est especificando el tipo de excepcin que puede generar (en lugar de un objeto Exception).
He aqu un ejemplo, tomado del sistema Java de entrada/salida:
byte readByte() throws IOException; short readShort() throws IOException; char readChar() throws IOException; void writeByte( int v ) throws IOException; void writeShort( int v ) throws IOException; void writeChar( int v ) throws IOException; Lo ms interesante aqu es que la rutina que lee un char, puede devolver un char; no el entero que se requiere en C. C necesita que se devuelva un int, para poder pasar cualquier valor a un char, y adems un valor extra (-1) para indicar que se ha alcanzado el final del fichero. Algunas de las rutinas Java lanzan una excepcin cuando se alcanza el fin del fichero.
Cuando se crea una nueva excepcin, derivando de una clase Exception ya existente, se puede cambiar el mensaje que lleva asociado. La cadena de texto puede ser recuperada a travs de un mtodo.
Normalmente, el texto del mensaje proporcionar informacin para resolver el problema o sugerir una accin alternativa. Por ejemplo:
class SinGasolina extends Exception { SinGasolina( String s ) { // constructor super( s ); } .... // Cuando se use, aparecer algo como esto try { if( j < 1 ) throw new SinGasolina( "Usando deposito de reserva" ); } catch( SinGasolina e ) { System.out.println( o.getMessage() ); }
Esto, en tiempo de ejecucin originara la siguiente salida por pantalla:
> Usando deposito de reserva Otro mtodo que es heredado de la superclase Throwable es printStackTrace(). Invocando a este mtodo sobre una excepcin se volcar a pantalla todas las llamadas hasta el momento en donde se gener la excepcin (no donde se maneje la excepcin). Por ejemplo:
// Capturando una excepcin en un mtodo class testcap { static int slice0[] = { 0,1,2,3,4 }; public static void main( String a[] ) { try { uno(); } catch( Exception e ) { System.out.println( "Captura de la excepcion en main()" ); e.printStackTrace(); } } static void uno() { try { slice0[-1] = 4; } catch( NullPointerException e ) { System.out.println( "Captura una excepcion diferente" ); } } }
Cuando se ejecute ese cdigo, en pantalla observaremos la siguiente salida:
> Captura de la excepcion en main() > java.lang.ArrayIndexOutOfBoundsException: -1 at testcap.uno(test5p.java:19) at testcap.main(test5p.java:9)
Con todo el manejo de excepciones podemos concluir que se proporciona un mtodo ms seguro para el control de errores, adems de representar una excelente herramienta para organizar en sitios concretos todo el manejo de los errores y, adems, que se pueden proporcionar mensajes de error ms decentes al usuario indicando qu es lo que ha fallado y por qu, e incluso podemos, a veces, recuperar al programa automticamente de los errores.
La degradacin que se produce en la ejecucin de programas con manejo de excepciones est ampliamente compensada por las ventajas que representa en cuanto a seguridad de funcionamiento de esos mismos programas. 5.4 Gestin de excepciones
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. Generacion de exepciones
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:
public class Empresa { String nombre; Empleado [] listaEmpleados; int totalEmpleados = 0; . . . Empresa(String n, int maxEmp) { nombre = n; listaEmpleados = new Empleado [maxEmp]; } . . . void nuevoEmpleado(String nombre, int sueldo) { if (totalEmpleados < listaEmpleados.length ) { listaEmpleados[totalEmpleados++] = new Empleado(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:
void nuevoEmpleado(String nombre, int sueldo) throws CapacidadEmpresaExcedida { if (totalEmpleados < listaEmpleados.length) { listaEmpleados[totalEmpleados++] = new Empleado(nombre,sueldo); } else throw new CapacidadEmpresaExcedida(nombre); }
Adems, necesitamos escribir la clase CapacidadEmpresaExcedida. Sera algo as: public class CapacidadEmpresaExcedida extends Exception { CapacidadEmpresaExcedida(String nombre) { super("No es posible aadir el empleado " + 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.
5.5 Creacin y manejo de excepciones creadas por el usuario
Las excepciones predefinidas cubren las situaciones de error ms habituales con las que nos podemos encontrar, relacionadas con el propio lenguaje y el hardware. Cuando se desarrollan aplicaciones existen otras situaciones de error de ms alto nivel relacionadas con la funcionalidad de nuestros programas.
Imaginemos una aplicacin informtica que controla la utilizacin de los remontes de una estacin de esqu: los pases de acceso a los remontes son personales e intransferibles y dispondrn de un cdigo de barras que los identifica. Cada vez que un usuario va a hacer uso de un remonte debe introducir su pase de acceso en una mquina de validacin, que a cciona un torno y devuelve el pase. El sistema puede constar de un ordenador central al que le llegan telemticamente los datos correspondientes a los cdigos de barras de los pases que en cada momento se estn introduciendo en cada mquina de validacin d e cada remonte; si un cdigo de barras est en regla, el ordenador enva una orden de liberar el torno para permitir al usuario acceder al remonte. El ordenador central habitualmente recibir cdigos correctos utilizados en momentos adecuados, sin embargo, en ciertas ocasiones nos encontraremos con situaciones anmalas:
1 Cdigo de barras ilegible
2 Cdigo de barras no vlido (por ejemplo correspondiente a un pase caducado)
3 Cdigo de barras utilizado en otro remonte en un periodo de tiempo demasiado breve
Antes de nada tenemos que tener en cuenta que el mecanismo de excepciones es muy lento en ejecucin comparado con la utilizacin de instrucciones condicionales. Aunque el mecanismo de excepciones es elegante, debemos utilizarlo con prudencia: nicamente en situaciones que realmente son excepcionales.
Definicin de una excepcin definida por el programador
En programacin orientada a objetos lo ms adecuado es que las excepciones sean objetos, por lo que en Java definiremos las excepciones como clases. Nuestras clases de excepcin, en general, heredarn de la clase Exception.
En las clases que nos creemos a partir de Exception, incluiremos al menos el constructor vaco y otro que contenga un String como argumento. Este String se inicializa automticamente con el nombre de la clase; la inicializacin se realiza en la superclase Throwable. El texto que pongamos al hacer uso del segundo constructor se aadir al nombre de la clase insertado por la superclase.
A continuacin se presenta una clase (ExPropia) muy simple que define una excepcin propia:
1 public class ExPropia extends Exception { 2 3 ExPropia () { 4 super("Esta es mi propia excepcion"); 5 } 6 7 ExPropia (String s) { 8 super(s); 9 } 10 11 }
En la lnea 1 se define nuestra clase Expropia que hereda de Exception. La lnea 3 define el constructor vaco, que en este caso aade el texto Esta es mi propia excepcion al nombre de la clase, quedando ExPropia: Esta es mi propia excepcion. La lnea 7 define el constructor con un String como argumento; nos servir para aadir el texto que deseemos al instanciar la clase.