next up previous contents
Siguiente: 10 Programación Multihilo (Multihebra) Subir: Introducción a Java y Anterior: 8 Paquetes e Interfaces   Índice General

Subsecciones

9 Gestión de excepciones

Una excepción es una condición anormal que surge en una secuencia de código durante la ejecución de un programa. O sea, es un error en tiempo de ejecución.

$ \Diamond$ Excepciones y errores

1 Fundamentos

Forma general de un bloque de gestión de excepciones

try {
  // bloque de código
}
catch (TipoExcepcion1 exOb){
  // gestor de excepciones para TipoExcepcion1
}
catch (TipoExcepcion2 exOb){
  // gestor de excepciones para TipoExcepcion2
}
// ...
finally {
  // bloque de código que se ejecutara antes de
  // que termine el bloque try
}

2 Tipos de excepción

Todos los tipos de excepción son subclase de Throwable. Esta clase tiene dos subclases:
  1. Exception: Se usa para las excepciones que deberían capturar los programas de usuario.
    Esta clase tiene como subclase a RuntimeException, que representa excepciones definidas automáticamente por los programas (división por 0, índice inválido de matriz, etc). Además tiene otras subclases como ClassNotFoundException, InterruptedException, etc.
  2. Error: Excepciones que no se suelen capturar en condiciones normales.
    Suelen ser fallos catastróficos no gestionados por nuestros programas. Ejemplo: desbordamiento de la pila. En CLDC 1.1 hay dos subclases de Error: VirtualMachineError y NoClassDefFoundError.


Image excepcionJerarquia



3 Excepciones no capturadas

Ejemplo: P32/Exc1.java

class Exc1 {
  static void subroutine() {
    int d = 0;
    int a = 10 / d;
  }
  public static void main(String args[]) {
    System.out.println("Antes de Exc1.subroutine");
    Exc1.subroutine();
    System.out.println("Despues de Exc1.subroutine");
  }
}

4 try y catch

Si incluimos nuestro propio gestor de excepciones evitamos que el programa termine automáticamente. Usaremos un bloque try-catch.

Ejemplo: P33/Exc2.java

class Exc2 {
  public static void main(String args[]) {
    int d, a;

    try { // controla un bloque de código.
      d = 0;
      a = 42 / d;
      System.out.println("Esto no se imprimirá.");
    }
    catch (ArithmeticException e) {// captura el error de división
      System.out.println("División por cero.");
    }
    System.out.println("Después de la sentencia catch.");
  }
}

El objetivo de una sentencia catch bien diseñada debería ser resolver la condición de excepción y continuar.

Otro ejemplo: P34/HandleError.java

// Gestiona una excepción y continua.
import java.util.Random;
class HandleError {
  public static void main(String args[]) {
    int a=0, b=0, c=0;
    Random r = new Random();
    for(int i=0; i<32000; i++) {
      try {
        b = r.nextInt();
        c = r.nextInt();
        a = 12345 / (b/c);
      } catch (ArithmeticException e) {
        System.out.println("Division por cero.");
        a = 0; // asigna a la variable el valor 0 y continua
      }
      System.out.println("a: " + a);
    }
  }
}

1 Descripción de una excepción

La clase Throwable sobreescribe el método toString() de la clase Object, devolviendo una cadena con la descripción de la excepción.

catch (ArithmeticException e) {
  System.out.println("Excepcion: " + e);
  a = 0; // hacer a=0 y continuar
}

Salida producida cuando se produce la excepción

Excepcion: java.lang.ArithmeticException

5 Cláusula catch múltiple

En algunos casos un bloque de código puede activar más de un tipo de excepción. Usaremos varios bloques catch.

El siguiente programa produce una excepción si se ejecuta sin parámetros y otra distinta si se ejecuta con un parámetro.

Ejemplo: P35/MultiCatch.java

class MultiCatch {
  public static void main(String args[]) {
    try {
      int a = args.length;
      System.out.println("a = " + a);
      int b = 42 / a;
      int c[] = { 1 };
      c[42] = 99;
    } catch(ArithmeticException e) {
      System.out.println("Division por 0: " + e);
    } catch(ArrayIndexOutOfBoundsException e) {
      System.out.println("Indice fuera de limites: " + e);
    }
    System.out.println("Despues del bloque try/catch.");
  }
}

Al ordenar los bloques catch, las subclases de excepción deben ir antes que la superclase (en caso contrario no se ejecutarían nunca y daría error de compilación por código no alcanzable).

Ejemplo: P36/SuperSubCatch.java

class SuperSubCatch {
  public static void main(String args[]) {
    try {
      int a = 0;
      int b = 42 / a;
    }
    catch(Exception e) {
      System.out.println("catch para cualquier tipo de excepción.");
    }
    /* Este catch nunca se ejecutará */
    catch(ArithmeticException e) { // ERROR - no alcanzable
      System.out.println("Esto nunca se ejecutará.");
    }
  }
}

6 Sentencias try anidadas

Ejemplo: P37/NestTry.java

class NestTry {
  public static void main(String args[]) {
    try {
      int a = args.length;
      /* Si no hay ningún argumento en la línea de órdenes
         se generará una excepción de división por cero. */
      int b = 42 / a;
      System.out.println("a = " + a);
      try { // bloque try anidado
        /* Si se utiliza un argumento en la línea de órdenes
           se generará una excepción de división por cero. */
        if(a==1) a = a/(a-a); // división por cero
        /* Si se le pasan dos argumentos en la línea de órdenes,
           se genera una excepción al sobrepasar los límites
           del tamaño de la matriz. */
        if(a==2) {
          int c[] = { 1 };
          c[42] = 99; // genera una excepción de fuera de límites
        }
      } catch(ArrayIndexOutOfBoundsException e) {
        System.out.println("Indice fuera de limites: " + e);
      }
    } catch(ArithmeticException e) {
      System.out.println("División por 0: " + e);
    }
  }
}

$ \Diamond$ Sentencias try anidadas en forma menos obvia

Ejemplo: P38/MethNestTry.java

/* Las sentencias try pueden estar implícitamente anidadas
   a través de llamadas a métodos. */
class MethNestTry {
  static void nesttry(int a) {
    try { // bloque try anidado
      /* Si se utiliza un argumento en la línea de órdenes, la
         siguiente sentencia efectúa división por cero */
      if(a==1) a = a/(a-a); // división por zero
      /* Si se le pasan dos argumentos en la línea de órdenes,
         se sobrepasan los límites de la matriz */
      if(a==2) {
        int c[] = { 1 };
        c[42] = 99; // genera una excepción de fuera de límites
      }
    } catch(ArrayIndexOutOfBoundsException e) {
      System.out.println("Indice fuera de limites: " + e);
    }
  }

  public static void main(String args[]) {
    try {
      int a = args.length;
      /* Si no hay ningún argumento en la línea de órdenes, la
         siguiente sentencia generará una excepción de división
         por cero */
      int b = 42 / a;
      System.out.println("a = " + a);
      nesttry(a);
    } catch(ArithmeticException e) {
      System.out.println("División por 0: " + e);
    }
  }
}

7 Lanzar excepciones explícitamente: throw

Usando la sentencia throw es posible hacer que el programa lance una excepción de manera explícita: throw objetoThrowable;

El objetoThrowable puede obtenerse mediante:

  1. El parámetro de una sentencia catch.
  2. Con el operador new .

Ejemplo: P39/ThrowDemo.java

class ThrowDemo {
  static void demoproc() {
    try {
      throw new NullPointerException("demo");
    } catch(NullPointerException e) {
      System.out.println("Captura dentro de demoproc.");
      throw e; // relanza la excepción
    }
  }

  public static void main(String args[]) {
    try {
      demoproc();
    } catch(NullPointerException e) {
      System.out.println("Nueva captura: " + e);
    }
  }
}

El flujo de ejecución se detiene tras la sentencia throw (cualquier sentencia posterior no se ejecuta).

Salida del anterior ejemplo:

Captura dentro de demoproc.
Nueva captura: java.lang.NullPointerException: demo

8 Sentencia throws

Sirve para listar los tipos de excepción que un método puede lanzar.

Forma general de declaración de método con throws

tipo metodo(lista_de_parametros) throws lista_de_excepciones
{
  // cuerpo del metodo
}

Ejemplo: P40/ThrowsDemo.java

// Programa erróneo que no compila
class ThrowsDemo {
  static void throwOne() {
    System.out.println("Dentro de throwOne.");
    throw new IllegalAccessException("demo");
  }
  public static void main(String args[]) {
    throwOne();
  }
}

El método que use al del throws debe capturar todas las excepciones listada con el throws.

Ejemplo: P41/ThrowsDemo.java

// Programa correcto
class ThrowsDemo {
  static void throwOne() throws IllegalAccessException {
    System.out.println("Dentro de throwOne.");
    throw new IllegalAccessException("demo");
  }
  public static void main(String args[]) {
    try {
      throwOne();
    } catch (IllegalAccessException e) {
      System.out.println("Captura " + e);
    }
  }
}

9 Sentencia finally

Ejemplo de uso de finally: P42/FinallyDemo.java

class FinallyDemo {
  static void procA() {// Lanza una excepción fuera del metodo
    try {
      System.out.println("Dentro de procA");
      throw new RuntimeException("demo");
    } finally {
      System.out.println("Sentencia finally de procA");
    }
  }
  static void procB() {// Ejecuta la sentencia return 
                       // dentro del try
    try {
      System.out.println("Dentro de procB");
      return;
    } finally {
      System.out.println("Sentencia finally de procB");
    }
  }
  static void procC() {// Ejecuta un bloque try normalmente
    try {
      System.out.println("Dentro de procC");
    } finally {
      System.out.println("Sentencia finally de procC");
    }
  }

  public static void main(String args[]) {
    try {procA();
    } catch (Exception e) {
      System.out.println("Excepción capturada");
    }
    procB(); procC();
  }
}

Salida del anterior programa

Dentro de procA
Sentencia finally de procA
Excepción capturada
Dentro de procB
Sentencia finally de procB
Dentro de procC
Sentencia finally de procC

10 Subclases de excepciones propias

Ejemplo: P43/ExceptionDemo.java

class MyException extends Exception {
  private int detail;
  MyException(int a) {
    detail = a;
  }
  public String toString() {
    return "MyException[" + detail + "]";
  }
}
class ExceptionDemo {
  static void compute(int a) throws MyException {
    System.out.println("Ejecuta compute(" + a + ")");
    if(a > 10)
      throw new MyException(a);
    System.out.println("Finalización normal");
  }
  public static void main(String args[]) {
    try {
      compute(1);
      compute(20);
    } catch (MyException e) {
      System.out.println("Captura " + e);
    }
  }
}
La salida de este programa sería:
Ejecuta compute(1)
Finalización normal
Ejecuta compute(20)
Captura MyException[20]


next up previous contents
Siguiente: 10 Programación Multihilo (Multihebra) Subir: Introducción a Java y Anterior: 8 Paquetes e Interfaces   Índice General
Andres Cano Utrera 2006-09-23