## Los bloques catch

Como se aprendió en la página anterior, la sentencia try define el ámbito de sus manejadores de excepción asociados. Se pueden asociar manejadores de excepción a una sentencia try proporcionando uno o más bloques catch directamente después del bloque try:

    try {
        . . .
    } catch ( . . . ) {
        . . .
    } catch ( . . . ) {
        . . .
    } . . .

No puede haber ningún código entre el final de la sentencia try y el principio de la primera sentencia catch. La forma general de una sentencia catch en Java es esta:

    catch (AlgunObjetoThrowable nombreVariable) {
        Sentencias Java
    }

Como puedes ver, la sentencia catch requiere un sólo argumento formal. Este argumento parece un argumento de una declaración de método. El tipo del argumento AlgunObjetoThrowable declara el tipo de excepción que el manejador puede manejar y debe ser el nombre de una clase heredada de la clase Throwable definida en el paquete java.lang. (Cuando los programas Java lanzan una excepción realmente están lanzado un objeto, sólo pueden lanzarse los objetos derivados de la clase Throwable. Aprenderás cómo lanzar excepciones en la lección ¿Cómo Lanzar Excepciones?.)

nombreVariable es el nombre por el que el manejador puede referirse a la excepción capturada. Por ejemplo, los manejadores de excepciones para el método writeList() (mostrados más adelante) llaman al método getMessage() de la excepción utilizando el nombre de excepción declarado e:

    e.getMessage()

Se puede acceder a las variables y métodos de las excepciones en la misma forma que accede a los de cualquier otro objeto. getMessage() es un método proporcionado por la clase Throwable que imprime información adicional sobre el error ocurrido. La clase Throwable también implementa dos métodos para rellenar e imprimir el contenido de la pila de ejecución cuando ocurre la excepción. Las subclases de Throwable pueden añadir otros métodos o variables de ejemplar, Para buscar qué metodos implementar en una excpeción, se puede comprobar la definición de la clase y las definiciones de las clases antecesoras.

El bloque catch contiene una serie de sentencias Java legales. Estas sentencias se ejecutan cuando se llama al manejador de excepción. El sistema de ejecución llama al manejador de excepción cuando el manejador es el primero en la pila de llamadas cuyo tipo coincide con el de la excepción lanzada.

El método writeList() de la clase de ejemplo ListOfNumbers utiliza dos manejadores de excepción para su sentencia try, con un manejador para cada uno de los tipos de excepciones que pueden lanzarse dentro del bloque try -- ArrayIndexOutOfBoundsException y IOException.

    try {
        . . .
    } catch (ArrayIndexOutOfBoundsException e) {
        System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
    } catch (IOException e) {
        System.err.println("Caught IOException: " + e.getMessage());
    }

### Ocurre una IOException

> Supongamos que ocurre una excepción IOException dentro del bloque try. El sistema de ejecución inmediantamente toma posesión e intenta localizar el manejador de excepción adecuado. El sistema de ejecución empieza buscando al principio de la pila de llamadas. Sin embargo, el constructor de FileOutputStream no tiene un manejador de excepción apropiado por eso el sistema de ejecución comprueba el siguiente método en la pila de llamadas -- el método writeList(). Este método tiene dos manejadores de excepciones: uno para ArrayIndexOutOfBoundsException y otro para IOException.

> El sistema de ejecución comprueba los manejadores de writeList() por el orden en el que aparecen después del bloque try. El primer manejador de excepción cuyo argumento corresponda con el de la excepción lanzada es el elegido por el sistema de ejecución. (El orden de los manejadores de excepción es importante!) El argumento del primer manejador es una ArrayIndexOutOfBoundsException, pero la excepción que se ha lanzado era una IOException. Una excepción IOException no puede asignarse legalmente a una ArrayIndexOutOfBoundsException, por eso el sistema de ejecución continúa la búsqueda de un manejador de excepción apropiado.

> El argumento del segundo manejador de excepción de writeList() es una IOException. La excepción lanzada por el constructor de FileOutputStream también es un una IOException y por eso puede ser asignada al argumento del manejador de excepciones de IOException. Así, este manejador parece el apropiado y el sistema de ejecución ejecuta el manejador, el cual imprime esta sentencia:

>     Caught IOException: OutFile.txt

> El sistema de ejecución sigue un proceso similar si ocurre una excepción ArrayIndexOutOfBoundsException. Para más detalles puedes ver: Poniéndolo todo Junto que te lleva a través de método writeList() después de haberlo completado (queda un paso más) e investiga lo que sucede en varios escenarios.

### Capturar Varios Tipos de Excepciones con Un Manejador

> Los dos manejadores de excepción utilizados por el método writeList() son muy especializados. Cada uno sólo maneja un tipo de excepción. El lenguaje Java permite escribir manejadores de excepciones generales que pueden manejar varios tipos de excepciones.

> Como ya sabes, las excepciones Java son objetos de la clase Throwable (son ejemplares de la clase Throwable a de alguna de sus subclases). Los paquetes Java contienen numerosas clases derivadas de la clase Throwable y así construyen un árbol de clases Throwable.

> El manejador de excepción puede ser escrito para manejar cualquier calse heredada de Throwable. Si se escribe un manejador para una clase 'hoja? (una clase que no tiene subclases), se habrá escrito un manejador especializado: sólo maneja excepciones de un tipo específico. Si se escribe un manejador para una clase 'nodo' (una clase que tiene subclases), se habrá escrito un manejador general: se podrá manejar cualquier excepción cuyo tipo sea el de la clase nodo o de cualquiera de sus subclases.

> Módifiquemos de nuevo el método writeList(). Sólo esta vez, escribamoslo para que maneje las dos excepciones IOExceptions y ArrayIndexOutOfBoundsExceptions. El antecesor más cercano de estas dos excepciones es la clase Exception. Así un manejador de excepción que quisiera manejar los dos tipos se parecería a esto:

>     try {
>         . . .
>     } catch (Exception e) {
>         System.err.println("Exception caught: " + e.getMessage());
>     }

> La clase Exception está bastante arriba en el árbol de herencias de la clase Throwable. Por eso, además de capturar los tipos de IOException y ArrayIndexOutOfBoundsException este manejador de excepciones, puede capturar otros muchos tipos. Generalmente hablando, los manejadores de excepción deben ser más especializados.

> Los manejadores que pueden capturar la mayoría o todas las excepciones son menos utilizados para la recuperacón de errores porque el menejador tiene que determinar qué tipo de excepción ha ocurrido de todas formas (para determinar la mejor estrategia de recuperación). Los manejadores de excepciones que son demasiado generales pueden hacer el código más propenso a errores mediante la captura y menejo de excepciones que no fueron anticipadas por el programador y para las que el manejador no está diseñado.

Ozito