G.Bordel >Docencia >TAP Técnicas Actuales de Programación (curso 2010-2011)
desprotegido Intro. desprotegido Temario desprotegido Calendario desprotegido RPF desprotegido Recursos protegido Práctica protegido Gest. Alum.
tema_anterior Tema 5: Mecanismo de tratamiento de Excepciones y Errores tema_siguiente
  1. Introducción.
  2. Control de excepciones.
  3. Generación excepciones.
  4. Definición de nuevas excepciones.[ejercicios]

5.2- Control de excepciones

Germán Bordel - Docencia - Doctorado (con Angel Franco)
Palabras reservadas en Java
abstractbooleanbreakbytecasecatch
charclassconst*continuedefaultdo
doubleelseextendsfinalfinallyfloat
forgoto*ifimplementsimportinstanceof
intinterfacelongnativenewpackage
privateprotectedpublicreturnshortstatic
strictfp**superswitchsynchronizedthisthrow
throwstransienttryvoidvolatilewhile

La separación de losbloques de código para una ejecución normal y para sus posibles situaciones excepcionales se lleva a cabo mediante una sentencia que se dejo sin ver en su momento para hecerlo ahora. se trata de la sentencia:

try sentencia [catch (clase_arrojable id) sentencia]+ finally sentencia

donde la sentencia que acompaña a try (normalmente un bloque {...}), se corresponderá con el algoritmo a ejecutar en caso de que no surjan excepciones, y cada posible situación excepcional será atendida por una sentencia (normalmente un bloque) asociada a un catch (la "captura" de un objeto arrojado en el momento de la excepción). Como puede verse, puede haber uno o más fragmentos "catch" conforme sea necesario por el número de situaciones excepcionales posibles en el código "normal". Estos fragmentos tienen, como si de rutinas se tratase, un parámetro al que se le da un identificador (id) que será de una determinada clase "arrojable". Cuando se produzca una situación en que se arroje un objeto de una determinada clase, será recogido por el fragmento catch que tenga el parámetro correspondiente.

Por último se tiene un fragmento finally que será ejecutado siempre una vez que se haya terminado la ejecución del try y los catch. Su función es la de terminar con todas aquellos requerimientos que han de darse aún cuando se hayan seguido diferentes caminos (distintas excepciones o la ejecución normal), como por ejemplo el cierre de ficheros, sockets, etc.

El siguiente ejemplo muestra esto y nos permite matizar alguna cuestión al respecto:

1-
2-
3-
4-
5-
6-
7-
8-
9-
10-
11-
12-
13-
14-
FileInputStream f=null;
int d;
try {
    f=new FileInputStream("pepe");
    d=f.read();
    // aqui el resto de acciones que se quieran realizar con f
} catch (FileNotFoundException e) {
    // aquí el código a ejecutar en caso de que no existiera el fichero "pepe"
} catch (IOException e) {
    // aquí el código a ejecutar en caso de que no se haya podido obtener f por otro motivo
} finally {
    if (f!=null) f.close();
    // aquí otro código que deba ejecutarse en todo caso
}

Aunque no se haya estudiado por ahora, puede entenderse facilmente que la clase FileInputStream es capaz de abrir un fichero para realizar lecturas de datos. En la linea 1 se declara una variable referencia para un objeto de tal clase y en la 2 una variable entera que podrá alojar un dato leido de un fichero. A continuación, en las lineas 3 a 7 se encuentra un bloque de código tras el término try que será el de la ejecución que queremos realizar con nuestro fichero; por ejemplo abrir uno que tiene nombre "pepe", leer un entero sobre la variable d, etc. De este modo puede escribirse el algoritmo a llevar a cabo sin "mezclarlo" con el control de situaciones excepcionales. Este control se hace a continuación: si consultamos la documentación de la clase FileInputStream, veremos que en el momento de instanciar un objeto puede producirse un error de clase FileNotFoundException que obedece a la situación evidenciada por su nombre, de modo que el bloque de las lineas 7 y 8, recibe un objeto de esta clase en caso de producirse y puede actuar en consecuencia (nótese que el código de este catch puede hacer uso del objeto recibido o no). Del mismo modo descubriremos en la documentaciñon del método read() que en el pueden producirse indeterminados errores de entrada/salida identificados con un objeto de clase IOException (p.ej. faltas de permisos de acceso, ausencia de datos sin fin de fichero, etc). Las acciones a ejecutar en tal caso se llevarian a cabo en el bloque 9-10. Si escribimos el total del bloque try es posible que aparezcan más situaciones de error que podran ser ser atendidas en otros bloques catch (si se repite más de una vez la misma clase de excepción, será atendida por el mismo bloque catch, y podrá llegarse a distinguir situaciones analizando el objeto recibido). Por último, el fragmento finally de las líneas 11-14 se ocupará de terminar con todo aquello que pueda haber quedado en situación inconclusa, como por ejemplo de cerrar el fichero en caso de que se hubiese llegado a abrir.

Hay que mencionar dos detalles importantes...

En primer lugar que, dado que los objetos arrojables pertenecen a una jerarquía, hay que ser cuidadoso al situar los catch, ya que el objeto será recogido por el primer catch que se ajuste a su clase teniendo en cuenta la capacidad de polimorfismo. Por ejemplo, dado que FileNotFoundException es una clase descenciente de la clase , un objeto dicha clase puede considerarse tambien de ésta última, de modo que si hubiesemos escrito los bloques catch en orden inverso el asociado a FileNotFoundException quedaría anulado al ser atendidas las excepciones de esta clase por el catch de IOException (este problema es detectado por el compilador)

En segundo lugar hay que reforzar la idea de que el bloque finally se realiza siempre, y esto es así hasta el punto de que incluso aún cuando se encuentre un return en algún punto de los bloques try o catch, se ejecutará el finally antes de llevarlo a cabo. Veamoslo con unejemplo amliado del anterior:

1-
2-
3-
4-
5-
6-
7-
8-
9-
10-
11-
12-
13-
14-
15-
16-
17-
18-
19-
public void procesaPepe() {
  FileInputStream f=null;
  int d;
  try {
      f=new FileInputStream("pepe");
      d=f.read();
      // aqui el resto de acciones que se quieran realizar con f
  } catch (FileNotFoundException e) {
      // aquí el código a ejecutar en caso de que no existiera el fichero "pepe"
      return;
  } catch (IOException e) {
      // aquí el código a ejecutar en caso de que no se haya podido obtener f por otro motivo
      return;
  } finally {
      if (f!=null) f.close();
      // aquí otro código que deba ejecutarse en todo caso
  }
  // más código del método
}

Aquí un método consiste en una sentencia try-actch-finally y más código a continuación. En una ejecución normal se llevarán a cabo las acciones del bloque try, a continuación las del bloque finally y despues el resto del código del método. En una ejecucióncon una excepcion, el bloque try se abortará, se ejecutará el catch correspondiente que acaba con un return pero antes de terminar (de ejecutar el "retorno") se ejecutará el bloque finally.

El único modo de que no se ejecute el bloque finally es que se produzca la terminación de la aplicación (mediante System.exit(int)).

Ejemplo "externo" de uso: procesamiento de un parámetro en una jsp
//Se supone que el cliente no tiene código de promoción 
     int codigoPromocion=0;
//Se comprueba si llega código como parámetro
     try {
         codigoPromocion=Integer.parseInt(request.getParameter("codP"));
         };
//Si no hay código o no es numérico se continua normalmente
     catch (NumberFormatException ex) {}
     catch (NullPointerException ex) {}

Siguiente punto: 5.3- Generación excepciones


Plataforma de soporte a curso y contenidos (c) German Bordel 2005.