Las excepciones estándar

chapter.gif (1105 bytes)home.gif (1054 bytes)next.gif (998 bytes)

Las excepciones

Las excepciones

Captura de las excepciones

Manejando varias excepciones


Los programadores de cualquier lenguaje se esfuerzan por escribir programas libres de errores, sin embargo, es muy difícil que los programas reales se vean libres de ellos. En Java las situaciones que pueden provocar un fallo en el programa se denominan excepciones.

Java lanza una excepción en respuesta a una situación poco usual. El programador también puede lanzar sus propias excepciones. Las excepciones en Java son objetos de clases derivadas de la clase base Exception. Existen también los errores internos que son objetos de la clase Error que no estudiaremos. Ambas clases Error y Exception son clases derivadas de la clase base Throwable.

Existe toda una jerarquía de clases derivada de la clase base Exception. Estas clases derivadas se ubican en dos grupos principales:

Las excepciones en tiempo de ejecución ocurren cuando el programador no ha tenido cuidado al escribir su código. Por ejemplo, cuando se sobrepasa la dimensión de un array se lanza una excepción ArrayIndexOutOfBounds. Cuando se hace uso de una referencia a un objeto que no ha sido creado se lanza la excepción NullPointerException. Estas excepciones le indican al programador que tipos de fallos tiene el programa y que debe arreglarlo antes de proseguir.

El segundo grupo de excepciones, es el más interesante, ya que indican que ha sucedido algo inesperado o fuera de control.

 

Las excepciones

En la página dedicada al estudio de la clase String, mencionamos una función que convierte un string en un número. Esta función es muy usuada cuando creamos applets. Introducimos el número en un control de edición, se obtiene el texto y se guarda en un string. Luego, se convierte el string en número entero mediante la función estática Integer.parseInt, y finalmente, usamos dicho número.

	String str="  12 ";
	int numero=Integer.parseInt(str);

Si se introducen caracteres no numéricos, o no se quitan los espacios en blanco al principio y al final del string, mediante la función trim, se lanza una excepción NumberFormatException.

AppAccelerator(tm) 1.1.034 for Java (JDK 1.1), x86 version.
Copyright (c) 1998 Borland International. All Rights Reserved.

java.lang.NumberFormatException: 12
        at java.lang.Integer.parseInt(Compiled Code)
        at java.lang.Integer.parseInt(Integer.java:390)
        at excepcion.ExcepcionApp.main(ExcepcionApp.java:8)

Para ver este texto, se selecciona el elemento del menú del IDE Run/Parematers. En el cuadro de diálogo que aparece activar el botón de radio Set run output to Execution Log. Luego, se corre la aplicación Run/Run. Se selecciona el elemento del menú View/Execution Log, para que se muestre en una ventana la salida del programa.  Para restaurar la salida a la consola, la ventana DOS, se selecciona de nuevo Run/Parematers. En el cuadro de diálogo que aparece, se activa el botón de radio Set run output to Console window.

El mensaje que aparece en la ventana nos indica el tipo de excepción NumberFormatException, la función que la ha lanzado Integer.parseInt, que se llama dentro de main.

Objeto no inicializado

Habitualmente, cuando llamanos desde un objeto no inicializado, a una función miembro.

    public static void main(String[] args) {
	String str;
        str.length();
	//...
   }

El compilador se queja con el siguiente mensaje "variable str might not have been initilized". En otras ocasiones, se lanza una excepción del tipo NulPointerException. Fijarse que en la porción de código que sigue, grafico es una variable de instancia que es inicializada por defecto a null.

class MiCanvas....{
	Grafico grafico;
    public void paint(...){
	grafico.dibuja();
	//...
    }
//...
}

Como vemos en la porción de código, si al llamarse a la función paint, el objeto grafico no ha sido inicializado con el valor devuelto por new al crear un objeto de la clase Grafico o de alguna de sus clases derivadas, se lanza la excepción NullPointerException apareciendo en la consola el siguiente texto.

Exception occurred during event dispatching:
java.lang.NullPointerException
        at grafico1.MiCanvas.paint(MiCanvas.java:43)
        at sun.awt.windows.WComponentPeer.handleEvent(Compiled Code)
        at java.awt.Component.dispatchEventImpl(Compiled Code)
        at java.awt.Component.dispatchEvent(Compiled Code)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

 

Entrada/salida

En otras situaciones el mensaje de error aparece en el momento en el que se compila el programa. Así, cuando intentamos leer un carácter del teclado, llamamos a la la función

        System.in.read();

Cuando compilamos el programa, nos aparece un mensaje de error que no nos deja proseguir.

unreported exception: java.io.IOException; must be caught or declared to be thrown

 

Captura de las excepciones

Empecemos por solucionar el error que se produce en el programa durante la compilación. Tal como indica el mensaje que genera el compilador, se ha de poner la sentencia System.in.read(); en un bloque try...catch, del siguiente modo.

    	try {
        	System.in.read();
    	}catch (IOException ex) {  }

Para solucionar el error que se produce en el programa durante su ejecución, se debe poner la llamada a Integer.parseInt en el siguiente bloque  try...catch.

	String str="  12 ";
	int numero;
    	try{
        	numero=Integer.parseInt(str);
    	}catch(NumberFormatException ex){
        	System.out.println("No es un número");
    	}

En el caso de que el string str contenga caracteres no numéricos como es éste el caso, el número 12 está acompñado de espacios en blanco, se produce una excepción del tipo NumberFormatException que es capturada y se imprime el mensaje "No es un número".

En vez de un mensaje propio se puede imprimir el objeto ex de la clase NumberFormatException

    	try{
		//...
	}catch(NumberFormatException ex){
        	System.out.println(ex);
    	}

La clase base Throwable de todas las clases que describen las excepciones, redefine la función toString, que devuelve el nombre de la clase que describe la excepción acompañado del mensaje asociado, que en este caso es el propio string str.

java.lang.NumberFormatException:    12 

Podemos extraer dicho mensaje mediante la función miembro getMessage, del siguiente modo

    	try{
		//...
	}catch(NumberFormatException ex){
        	System.out.println(ex.getMessage());
    	}

 

Manejando varias excepciones

disco.gif (1035 bytes) excepcion: ExcepcionApp.java

Vamos a crear un programa que divida dos números. Supongamos que los números se introducen én dos controles de edicion. Se obtiene el texto de cada uno de los controles de edición que se guardan en dos strings. En esta situación se pueden producir dos excepciones NumberFormatException, si se introducen caracteres no numéricos y ArithmeticException si se divide entre cero.

public class ExcepcionApp {
    public static void main(String[] args) {
        String str1="12";
	String str2="0";
        String respuesta;
	int numerador, denominador, cociente;
        try{
            numerador=Integer.parseInt(str1);
            denominador=Integer.parseInt(str2);
            cociente=numerador/denominador;
            respuesta=String.valueOf(cociente);
        }catch(NumberFormatException ex){
            respuesta="Se han introducido caracteres no numéricos";
        }catch(ArithmeticException ex){
            respuesta="División entre cero";
        }
        System.out.println(respuesta);
    }
}

Como vemos las sentencias susceptibles de lanzar una excepción se sitúan en un bloque try...catch. Si el denominador es cero, se produce una excepción de la clase ArithmeticException en la expresión que halla el cociente, que es inmediatamente capturada en el bloque catch que maneja dicha excepción, ejecutándose las sentencias que hay en dicho bloque. En este caso se guarda en el string respuesta el texto "División entre cero".

Hay veces en las que se desea estar seguro de que un bloque de código se ejecute se produzcan o no excepciones. Se puede hacer esto añadiendo un bloque finally después del último catch. Esto es importante cuando accedemos a archivos, para asegurar que se cerrará siempre un archivo se produzca o no un error en el proceso de lectura/escritura.

	try{
		//Este código puede generar una excepción
	}catch(Exception ex){
		//Este código se ejecuta cuando se produce una excepción
	}finally{
		//Este código se ejecuta se produzca o no una excepción
	}