5. Manejo de las Excepciones

Una excepción es la indicación de que se produjo un error en el programa. Las excepciones, como su nombre lo indica, se producen cuando la ejecución de un método no termina correctamente, sino que termina de manera excepcional como consecuencia de una situación no esperada.

Cuando se produce una situación anormal durante la ejecución de un programa (por ejemplo se accede a un objeto que no ha sido inicializado o tratamos de acceder a una posición inválida en un vector), si no manejamos de manera adecuada el error que se produce, el programa va a terminar abruptamente su ejecución. Decimos que el programa deja de funcionar y es muy probable que el usuario que lo estaba utilizando ni siquiera sepa qué fue lo que pasó.

Cuando durante la ejecución de un método el computador detecta un error, crea un objeto de una clase especial para representarlo (de la clase Exception en Java), el cual incluye toda la información del problema, tal como el punto del programa donde se produjo, la causa del error, etc. Luego, "dispara" o "lanza" dicho objeto (throw en inglés), con la esperanza de que alguien lo atrape y decida como recuperarse del error. Si nadie lo atrapa, el programa termina, y en la consola de ejecución aparecerá toda la información contenida en el objeto que representaba el error. Este objeto se conoce como una excepción. En el ejemplo 1 se ilustra esta idea.

Ejemplo 1

Objetivo: Dar una idea global del concepto de excepción.

Este ejemplo ilustra el caso en el cual durante la ejecución de un método se produce un error y el computador crea un objeto para representarlo y permitir que en alguna parte del programa alguien lo atrape y lo use para evitar que el programa deje de funcionar.

public class C1
{
  private C2 atr;

  public void m1( )
  {
    atr.m2( );
  }
}
  • Suponga que tenemos una clase C1, en la cual hay un método llamado m1(), que es llamado desde las clases de la interfaz del programa.
  • Los objetos de la clase C1 tienen un atributo de la clase C2, llamado atr.
  • Suponga además que dentro del método m1() se invoca el método m2() de la clase C2 sobre el atributo llamado atr.
public  class  C2
{
  public void m2( )
  {
    instr1; 
    instr2; 
    instr3;
  }
}
  • Dentro de la clase C2 hay un método llamado m2() que tiene 3 instrucciones, que aquí mostramos como instr1, instr2, instr3. Dichas instrucciones pueden ser de cualquier tipo.
  • Suponga que se está ejecutando la instrucción instr2 del método m2() y se produce un error. En ese momento, a causa del problema el computador decide que no puede seguir con la ejecución del método (instr3 no se va a ejecutar).
  • Crea entonces un objeto de la clase Exception que dice que el error sucedió en la instrucción instr2 del método m2() y explica la razón del problema.
  • Luego, pasa dicho objeto al método m1() de la clase C1, que fue quien hizo la llamada. Si él lo atrapa (ya veremos más adelante cómo), el computador continúa la ejecución en el punto que dicho método indique.
  • Si el método m1() no atrapa la excepción, este objeto pasa a la clase de la interfaz que hizo la llamada. Este proceso se repite hasta que alguien atrape la excepción o hasta que el programa completo se detenga. Entendemos por manejar una excepción el hecho de poderla identificar, atraparla antes de que el programa deje de funcionar y realizar una acción para recuperarse del error (por lo menos, para informarle al usuario lo sucedido de manera amigable y no con un mensaje poco comprensible del computador).

En el resto de esta sección mostraremos cómo se hace todo el proceso anteriormente descrito, en el lenguaje de programación Java.

5.1. Anunciar que Puede Producirse una Excepción

Cuando en un método queremos indicar que éste puede disparar una excepción en caso de que detecte una situación que considera anormal, esta indicación debe formar parte de la signatura del método. En el ejemplo 2 se muestra la manera de hacer dicha declaración.

Ejemplo 2

Objetivo: Declarar que un método puede lanzar una excepción.

Este ejemplo muestra la manera de declarar en la signatura de un método que es posible que éste lance una excepción en caso de error. El método que se presenta forma parte de la clase Club y es responsable de afiliar un socio.

public void afiliarSocio( String pCedula, String pNombre, Tipo pTipo ) throws Exception
{
  ...
}
  • Con esta declaración el método advierte a todos aquellos que lo usan de que puede producirse una excepción al invocarlo. Los métodos que hacen la invocación pueden decidir atraparla o dejarla pasar.
  • No es necesario hacer un import de la clase Exception, puesto que esta clase está en un paquete que siempre se importa automáticamente (java.lang).

Al informar que un método lanza una excepción, estamos agrupando dos casos posibles: Caso 1: la excepción va a ser creada y lanzada por el mismo método que la declara. Esto quiere decir que es el mismo método el que se encarga de detectar el problema, de crear la instancia de la clase Exception y de lanzarla. Caso 2: la excepción fue producida por alguna instrucción en el cuerpo del método que hace la declaración, el cual decide no atraparla sino dejarla seguir. Este "dejarla seguir" se informa también con la misma cláusula throws.

5.2. La Instrucción try-catch

La instrucción try-catch de Java tiene la estructura que se muestra en la figura 4.7 y la sintaxis que se utiliza en el ejemplo 3.

Fig. 4.7 Estructura básica de la instrucción try-catch

En la instrucción try-catch hay dos bloques de instrucciones, con los siguientes objetivos:

  • Delimitar la porción de código dentro de un método en el que necesitamos desviar el control si una excepción ocurre allí (la parte try). Si se dispara una excepción en alguna de las instrucciones del bloque try, la ejecución del programa pasa inmediatamente a las instrucciones del bloque catch. Si no se dispara ninguna excepción en las instrucciones del bloque try, la ejecución continúa después del bloque catch.
  • Definir el código que manejará el error o atrapará la excepción (la parte catch).

Ejemplo 3

Objetivo: Mostrar el uso de la instrucción try-catch de Java.

Este método forma parte de alguna de las clases de la interfaz, en la cual existe una referencia hacia el modelo del mundo llamada club. La estructura y contenido de las clases que implementan la interfaz de usuario son el tema del siguiente nivel.

public void ejemplo( String pCedula, String pNombre, Tipo pTipo )
{
  try
  {
    club.afiliarSocio( pCedula, pNombre, pTipo ); 
    totalSocios++;
  }
  catch( Exception e )
  {
    String ms = e.getMessage( ); 
    JOptionPane.showMessageDialog( this, ms );
  }
}
  • Si en la llamada del método afiliarSocio se produce una excepción, ésta es atrapada y la ejecución del programa continúa en la primera instrucción del bloque catch. Note que en ese caso, la instrucción que incrementa el atributo totalSocios no se ejecuta.
  • La primera instrucción del bloque catch pide al objeto que representa la excepción el mensaje que explica el problema. Fíjese cómo utilizamos la variable e.
  • La segunda instrucción del bloque catch despliega una pequeña ventana de diálogo con el mensaje que traía el objeto e de la clase Exception. En este ejemplo, la intención es comunicarle al usuario que hubo un problema y que no se pudo realizar la afiliación del socio al club.

No todos los errores que se pueden producir en un método se atrapan con la instrucción catch(Exception). Existen los que se denominan errores de ejecución (dividir por cero, por ejemplo) que se manejan de una manera un poco diferente.

5.3. La Construcción de un Objeto Exception y la Instrucción throw

Cuando necesitamos disparar una excepción dentro de un método utilizamos la instrucción throw del lenguaje Java. Esta instrucción recibe como parámetro un objeto de la clase Exception, el cual es lanzado o disparado al método que corresponda, siguiendo el esquema planteado anteriormente. Lo primero que debemos hacer, entonces, es crear el objeto que representa la excepción, tal como se muestra en el ejemplo que aparece a continuación.

Ejemplo 4

Objetivo: Mostrar la manera de lanzar una excepción desde un método.

En este ejemplo aparece la implementación del método de la clase Club que permite afiliar un socio. En este método, si ya existe un socio con la misma cédula, se lanza una excepción, para indicar que se detectó una situación anormal.

public void afiliarSocio( String pCedula, String pNombre, Tipo pTipo ) throws Exception
{

  // En caso de que el tipo de suscripción del nuevo socio sea VIP, es necesario
  // revisar que no se haya alcanzado el límite de suscripciones VIP que maneja el club
  if( pTipo == Tipo.VIP && contarSociosVIP( ) == MAXIMO_VIP )
  {
    // Si ya se alcanzó el número máximo de suscripciones VIP, se lanza una excepción
    throw new Exception( "El club en el momento no acepta más socios VIP" );
  }

  // Revisar que no haya ya un socio con la misma cédula en el club
  Socio s = buscarSocio( pCedula );              

  if( s == null )
  {
    // Se crea el objeto del nuevo socio (todavía no se ha agregado al club)
    Socio nuevoSocio = new Socio( pCedula, pNombre, pTipo );

    // Se agrega el nuevo socio al club
    socios.add( nuevoSocio );
  }
  else
  {
    // Si ya existía un socio con la misma cédula, se lanza una excepción
    throw new Exception( "El socio ya existe" );
  }
}
  • Este método lanza una excepción a aquél que lo llama, si le pasan como parámetro la información de un socio que ya existe o si el socio que se desea afiliar tiene suscripción VIP y ya se alcanzó el máximo número de suscripciones VIP que maneja el club.
  • El constructor de la clase Exception recibe como parámetro una cadena de caracteres que describe el problema detectado.
  • Cuando un método atrape esta excepción y le pida su mensaje (getMessage()), el objeto va a responder con el mensaje que le dieron en el constructor.
  • En este ejemplo, cuando se detecta el problema se crea el objeto que representa el error y se lo lanza, todo de una sola vez. Pero podríamos haber hecho lo mismo en dos instrucciones separadas.

La clase Exception es una clase de Java que ofrece múltiples servicios, que se pueden consultar en la documentación. Los más usados son getMessage(), que retorna el mensaje con el que fue creada la excepción, y printStackTrace(), que imprime en la consola de ejecución la traza incluida en el objeto (la secuencia anidada de invocaciones de métodos que dio lugar al error), tratando de informar al usuario respecto de la posición y la causa del error.

Si utilizamos las siguientes instrucciones después de atrapar la excepción del método afiliarSocio() en caso de que ya exista un socio con la misma cédula, presentado en el ejemplo 4:

...
catch( Exception e )
{
  JOptionPane.showMessageDialog( this, e.getMessage( ) );
}

Obtendremos la ventana de advertencia al usuario que aparece en la figura 4.8.

Fig. 4.8 Despliegue de un mensaje de error como consecuencia de una excepción en el programa

5.4. Recuperación de una Situación Anormal

Cuando se está ejecutando un método, puede pasar que desde su interior se invoque otro método y, desde el interior de éste, otro y así sucesivamente. En la figura 4.9 mostramos un ejemplo de la ejecución de un método m1() que invoca un método m2(), el cual llama a m3() y este último a m4().

Fig. 4.9 Invocación en cascada de métodos

Supongamos ahora que durante la ejecución del método m4() se dispara una excepción. Es parte de nuestras decisiones de diseño decidir quién será el responsable de atraparla y manejarla. Una posibilidad es que el mismo método m4() la atrape y la procese. Otra posibilidad es que la responsabilidad se delegue hacia arriba, dejando que sea el método m3() o el método m2() o el método m1() quien se encargue de atrapar la excepción. En la figura 4.10 ilustramos la situación en que es el método m1() el responsable de hacerse cargo de la excepción.

Fig. 4.10 Flujo de control en el manejo de excepciones

El método encargado de atrapar una excepción utiliza la instrucción try-catch, mientras que los métodos que sólo la dejan pasar lo declaran en su signatura (throws Exception).

results matching ""

    No results matching ""