Excepciones

Manejo de Excepciones.

Las excepciones son la manera que ofrece Java de manejar los errores en tiempo de ejecución. Muchos lenguajes imperativos, cuando tenían un error de este clase lo que hacían era detener la ejecución del programa. Las excepciones nos permiten escribir código que nos permita manejar ese error y continuar (si lo estimamos conveniente) con la ejecución del programa.

El error en ejecución más clásico en Java es el de desbordamiento. Es decir, el intento de acceso a una posición de un vector que no existe. Por ejemplo:

 

Desbordamiento.java

public class Desbordamiento {

  static String mensajes[] = {"Primero", "Segundo", "Tercero" };

  public static void main(String[] args) {

    for (int i=0; i<=3; i++)

      System.out.println(mensajes[i]);

    System.out.println("Ha finalizado la ejecución");

  }

}

Este programa tendrá un serio problema cuando intente acceder a mensajes[3], pues no existe dicho valor. Al ejecutarlo nos dirá lo siguiente (o algo parecido):

 

Primero

Segundo

Tercero

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException

        at Desbordamiento.main(Desbordamiento.java, Compiled Code)

Nos da un error de ejecución (en esta terminología se diría que se lanzó una excepción) al intentar acceder a dicho valor inexistente. Vemos que, por ahora, el comportamiento de nuestro código es el mismo que en los lenguajes imperativos. Cuando encuentra el error, se para la ejecución. Ahora veremos como evitar esto.

 

try...catch...finally

 

Existe una estructura que nos permitirá capturar excepciones, es decir, reaccionar a un error de ejecución. De este modo podremos imprimir mensajes de error "a la medida" y continuar con la ejecución del programa si consideramos que el error no es demasiado grave. Para ver como funcionan vamos a modificar el ejemplo anterior, pero asegurandonos ahora de que capturamos las excepciones:

 

NuestroPrimerCatch.java

public class NuestroPrimerCatch {

  static String mensajes[] = {"Primero", "Segundo", "Tercero" };

  public static void main(String[] args) {

    try {

      for (int i=0; i&lt;=3; i++)

        System.out.println(mensajes[i]);

    }

    catch ( ArrayIndexOutOfBoundsException e ) {

      System.out.println("El asunto se nos ha desbordado");

    }

    finally {

      System.out.println("Ha finalizado la ejecución");

    }

  }

}

Dentro del bloque que sigue a try colocamos el código a ejecutar. Es como si dijeramos que vamos a intentar ejecutar dicho código a ver qué pasa. Después de try deberemos colocar al menos un bloque catch o un bloque finally, pudiendo tener ambos e incluso más de un bloque catch.

 

En el bloque finally ponemos el código que se ejecutará siempre, tanto si se lanza la excepción como si no. Su utilidad no es mucha, ya que si se permite continuar con la ejecución del programa basta con poner el código después del bloque try...catch. En nuestro ejemplo podríamos haber puesto lo siguiente:

 

    try {

      for (int i=0; i<=3; i++)

        System.out.println(mensajes[i]);

    }

    catch ( ArrayIndexOutOfBoundsException e ) {

      System.out.println("El asunto se nos ha desbordado");

    }

    System.out.println("Ha finalizado la ejecución");

Y habría funcionado exactamente igual. La miga está en los bloques catch.

 

Clase Exception

 

Cuando se lanza una excepción, en nuestro mundo orientado objetos lo que se hace es lanzar una instancia de Exception o de una clase derivada de él. Normalmente las clases derivadas no añaden mucha funcionalidad (muchas veces ninguna en absoluto), pero al ser distintas nos permiten distinguir entre los distintos tipos de excepciones.

 

En el programa anterior, por ejemplo, en el bloque catch capturábamos una excepción del tipo ArrayIndexOutOfBoundsException, ignorando cualquier otro tipo de excepción.

 

Esta clase tiene como cositas interesantes dos constructores y dos métodos (tiene más métodos pero sólo vamos a ver éstos):

 

Exception e = new Exception()

Crea una excepción si ningún mensaje específico.

Exception e = new Exception ( String )

Crea una excepción con un mensaje que detalla el tipo de excepción.

String e.getMessage()

Devuelve el mensaje detallado si existe o null en caso contrario.

void e.printStackTrace()

Escribe por la salida de error estándar una traza que nos permitirá localizar donde se generó el error. Es muy útil para depurar, pero no es conveniente que lo usuarios finales vean estas cosas.

Capturar excepciones

 

Ahora sabemos lo suficiente como para entender cómo funcionan los catch. Entre paréntesis, cual parámetro se pone la declaración de una excepción, es decir, el nombre de una clase derivada de Exception (o la misma Exception) seguido por el nombre de la variable. Si se lanza una excepción que es la que deseamos capturar o una derivada de la misma se ejecutará el código que contiene el bloque. Así, por ejemplo:

 

catch (Exception e) {

  ...

}

Se ejecutará siempre que se produzca una excepción del tipo que sea, ya que todas las excepciones se derivan de Exception. No es recomendable utilizar algo así ya que estamos capturando cualquier tipo de excepciones sin saber si eso afectará a la ejecución del programa o no.

 

Se pueden colocar varios bloques catch. En ese caso, se comprobará en orden si la excepción lanzada es la que deseamos capturar y si no pasa a comprobar la siguiente. Eso sí, sólo se ejecuta un bloque catch. En cuanto captura la excepción deja de comprobar los demás bloques. Por eso, lo siguiente:

catch (Exception e) {

  ...

}

catch (DerivadaDeException e) {

 ...

}

Regresar.