El bloque finally

El paso final en la creación de un manejador de excepción es proporcionar un mecanismo que limpie el estado del método antes (posiblemente) de permitir que el control pase a otra parte diferente del programa. Se puede hacer esto encerrando el código de limpieza dentro de un bloque finally.

El bloque try del método writeList() ha estado trabajando con un PrintStream abierto. El programa debería cerrar ese canal antes de pemitir que el control salga del método writeList(). Esto plantea un problema complicado, ya que el bloque try del writeList() tiene tres posibles salidas:

  1. La sentencia new FileOutputStream falla y lanza una IOException.
  2. La sentencia victor.elementAt(i) falla y lanza una ArrayIndexOutOfBoundsException.
  3. Todo tiene éxito y el bloque try sale normalmente.
El sistema de ejecución siempre ejecuta las sentencias que hay dentro del bloque finally sin importar lo que suceda dentro del bloque try. Esto es, sin importar la forma de salida del bloque try del método writeList() debido a los escenarios 1, 2 ó 3 listados arriba, el código que hay dentro del bloque finally será ejecutado de todas formas.

Este es el bloque finally para el método writeList(). Limpia y cierra el canal PrintStream.

finally {
    if (pStr != null) { 
        System.out.println("Closing PrintStream");
        pStr.close(); 
    } else { 
        System.out.println("PrintStream not open");
    } 
} 

¿Es realmente necesaria la sentencia finally?

La primera necesidad de la sentencia finally podría no aparecer de forma inmediata. Los programadores se preguntan frecuentemente "¿Es realmente necesaria la sentencia finally o es sólo azucar para mi Java?" En particular los programadores de C++ dudan de la necesidad de esta sentencia porque C++ no la tiene.

Esta necesidad de la sentencia finally no aparece hasta que se considera lo siguiente: ¿cómo se pordría cerrar el PrintStream en el método writeList() si no se proporcionara un manejador de excepción para la ArrayIndexOutOfBoundsException y ocurre una ArrayIndexOutOfBoundsException? (sería sencillo y legal omitir un manejador de excepción para ArrayIndexOutOfBoundsException porque es una excepción en tiempo de ejecución y el compilador no alerta de que writeList() contiene una llamada a un método que puede lanzar una).

La respuesta es que el PrintStream no se cerraría si ocurriera una excepción ArrayIndexOutOfBoundsException y writeList() no proporcionara u manejador para ella -- a menos que writeList() proporcionara una sentencia finally.

Existen otros beneficios de la utilización de la sentencia finally. En el ejemplo de writeList() es posible proporcionar un código de limpieza sin la intervención de una sentencia finally. Por ejemplo, podríamos poner el código para cerrar el PrintStream al final del bloque try y de nuevo dentro del manejador de excepción para ArrayIndexOutOfBoundsException, como se muestra aquí:

try {
    . . .
    pStr.close();       // No haga esto, duplica el código 
} catch (ArrayIndexOutOfBoundsException e) {
    pStr.close();       // No haga esto, duplica el código 
    System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
    System.err.println("Caught IOException: " + e.getMessage());
}
Sin embargo, esto duplica el código, haciéndolo díficil de leer y propenso a errores si se modifica más tarde, Por ejemplo, si se añade código al bloque try que pudiera lanzar otro tipo de excepción, se tendría que recordar el cerrar el PrintStream dentro del nuevo manejador de excepción (lo que se olvidará seguro si se parece a mí).


Ozito