miércoles, enero 07, 2015

Manejo de Excepciones en Java - Eclipse.

Un tema relevante en la programación, es el manejo y monitoreo de excepciones, por suerte en el lenguaje Java existe muchas alternativas que nos proveen la facilidad de controlar este tema facilmente.

En este url existe mas información del tema.

Resumiendo:

Excepciones Predefinidas
Las excepciones predefinidas por la implementación actual del lenguaje Java y su jerarquía interna de clases son las que se representan en el esquema de la figura que aparece a continuación:





Los nombres de las excepciones indican la condición de error que representan. Las siguientes son las excepciones predefinidas más frecuentes que se pueden encontrar:
ArithmeticException
Las excepciones aritméticas son típicamente el resultado de división por 0:
int i = 12 / 0;
NullPointerException
Se produce cuando se intenta acceder a una variable o método antes de ser definido:
class Hola extends Applet {
    Image img;

    paint( Graphics g ) {
        g.drawImage( img,25,25,this );
        }
    }
IncompatibleClassChangeException
El intento de cambiar una clase afectada por referencias en otros objetos, específicamente cuando esos objetos todavía no han sido recompilados.
ClassCastException
El intento de convertir un objeto a otra clase que no es válida.
y = (Prueba)x;      // donde x no es de tipo Prueba
NegativeArraySizeException
Puede ocurrir si hay un error aritmético al cambiar el tamaño de un array.
OutOfMemoryException
¡No debería producirse nunca! El intento de crear un objeto con el operador new ha fallado por falta de memoria. Y siempre tendría que haber memoria suficiente porque el garbage collector se encarga de proporcionarla al ir liberando objetos que no se usan y devolviendo memoria al sistema.
NoClassDefFoundException
Se referenció una clase que el sistema es incapaz de encontrar.
ArrayIndexOutOfBoundsException <
Es la excepción que más frecuentemente se produce. Se genera al intentar acceder a un elemento de un array más allá de los límites definidos inicialmente para ese array.
UnsatisfiedLinkException
Se hizo el intento de acceder a un método nativo que no existe. Aquí no existe un método a.kk()
class A {
    native void kk();
    }
y se llama a a.kk(), cuando debería llamar a A.kk().
InternalException
Este error se reserva para eventos que no deberían ocurrir. Por definición, el usuario nunca debería ver este error y esta excepción no debería lanzarse.
El compilador Java obliga al programador a proporcionar el código de manejo o control de algunas de las excepciones predefinidas por el lenguaje. Por ejemplo, el siguiente programa java902.java, no compilará porque no se captura la excepción InterruptedException que puede lanzar el método sleep().
import java.lang.Thread;

class java902 {
    public static void main( String args[] ) {
        java902 obj = new java902();
        obj.miMetodo();
        }
  
    void miMetodo() {
        // Aqui se produce el error de compilacion, porque no se esta
        // declarando la excepcion que genera este metodo
        Thread.currentThread().sleep( 1000 ); // currentThread() genera
                                              // una excepcion
        }
    }
Este es un programa muy simple, que al intentar compilar, producirá el siguiente error de compilación que se visualizará en la pantalla tal como se reproduce a continuación:
% javac java902.java
java902.java:41: Exception java.lang.InterruptedException must be caught,
or it must be declared in the throws clause of this method.
    Thread.currentThread().sleep( 1000 ); // currentThread() genera
                                ^
Como no se ha previsto la captura de la excepción, el programa no compila. El error identifica la llamada al método sleep() como origen del problema. Así que, la siguiente versión del programa, java903.java, soluciona el problema generado por esta llamada.
import java.lang.Thread;

class java903 {
    public static void main( String args[] ) {
        // Se instancia un objeto 
        java903 obj = new java903();
        // Se crea la secuencia try/catch que llamara al metodo que
        // lanza la excepcion
        try { 
            // Llamada al metodo que genera la excepcion
            obj.miMetodo();
            }catch(InterruptedException e){} // Procesa la excepcion
        }
  
    // Este es el metodo que va a lanzar la excepcion
    void miMetodo() throws InterruptedException {
        Thread.currentThread().sleep( 1000 ); // currentThread() genera
                                              // una excepcion
        }
    }
Lo único que se ha hecho es indicar al compilador que el método miMetodo() puede lanzar excepciones de tipo InterruptedException. Con ello conseguimos propagar las excepción que genera el método sleep() al nivel siguiente de la jerarquía de clases. Es decir, en realidad no se resuelve el problema sino que se está pasando a otro método para que lo resuelva él.
En el método main() se proporciona la estructura que resuelve el problema de compilación, aunque no haga nada, por el momento. Esta estructura consta de un bloque try y un bloque catch, que se puede interpretar como que intentará ejecutar el código del bloque try y si hubiese una nueva excepción del tipo que indica el bloque catch, se ejecutaría el código de este bloque, si ejecutar nada del try.
La transferencia de control al bloque catch no es una llamada a un método, es una transferencia incondicional, es decir, no hay un retorno de un bloque catch.
Crear Excepciones Propias
También el programador puede lanzar sus propias excepciones, extendiendo la clase System.exception. Por ejemplo, considérese un programa cliente/servidor. El código cliente se intenta conectar al servidor, y durante 5 segundos se espera a que conteste el servidor. Si el servidor no responde, el servidor lanzaría la excepción de time-out:
class ServerTimeOutException extends Exception {}

public void conectame( String nombreServidor ) throws Exception {
    int exito;
    int puerto = 80;

    exito = open( nombreServidor,puerto );
    if( exito == -1 )
        throw ServerTimeOutException;
    }
Si se quieren capturar las propias excepciones, se deberá utilizar la sentencia try:
public void encuentraServidor() {
   ...
   try {
        conectame( servidorDefecto );
        catch( ServerTimeOutException e ) {
            g.drawString( 
                "Time-out del Servidor, intentando alternativa",5,5 );
            conectame( servidorAlterno );
            }
    ...
    }
Cualquier método que lance una excepción también debe capturarla, o declararla como parte del interfaz del método. Cabe preguntarse entonces, el porqué de lanzar una excepción si hay que capturarla en el mismo método. La respuesta es que las excepciones no simplifican el trabajo del control de errores. Tienen la ventaja de que se puede tener muy localizado el control de errores y no hay que controlar millones de valores de retorno, pero no van más allá.
Y todavía se puede plantear una pregunta más, al respecto de cuándo crear excepciones propias y no utilizar las múltiples que ya proporciona Java. Como guía, se pueden plantear las siguientes cuestiones, y si la respuesta es afirmativa, lo más adecuado será implementar una clase Exception nueva y, en caso contrario, utilizar una del sistema.
  • ¿Se necesita un tipo de excepción no representado en las que proporciona el entorno de desarrollo Java?
  • ¿Ayudaría a los usuarios si pudiesen diferenciar las excepciones propias de las que lanzan las clases de otros desarrolladores?
  • ¿Si se lanzan las excepciones propias, los usuarios tendrán acceso a esas excepciones?
  • ¿El package propio debe ser independiente y auto-contenido?

No hay comentarios: