Excepciones en Java

Excepciones en Java

Si una operación no puede completarse debido a un error, el programa deberá:

  • volver a un estado estable y permitir otras operaciones

  • intentar guardar el trabajo y finalizar

Esta tarea es difícil debido a que generalmente el código que detecta el error no es el que puede realizar dichas tareas por eso debe informar al que pueda manejarlo

La solución más habitual son los códigos de error

Java ofrece otra forma de tratar con los errores en condiciones excepcionales: las excepciones

Una condición excepcional es aquella que impide la continuación de una operación

No se sabe como manejarla, pero no se puede continuar

En Java se lanza una excepción para que alguien que sepa manejarla la trate en un contexto superior

En el ejemplo se comprueba de forma condicional si el fichero readme.txt existía en el sistema y en caso de no existir se lanza la excepción IOException que de momento está sin tratar

La palabra reservada throw finaliza el método actual y lanza un objeto que facilite información sobre el error ocurrido

Normalmente se utilizará una clase para cada tipo de error

Java obliga a que un método informe de las excepciones explícitas que pueda lanzar

Un método no solo tiene que decir que devuelve si todo va bien; debe indicar también qué puede fallar

En el ejemplo se han declarado las excepciones EOFException y FileNotFoundException que afectaban al método fichero

La especificación de excepciones se realiza mediante la palabra throws en la declaración del método y puede haber tantas como necesitemos separadas por un espacio

Manejo de la excepciones

Una vez detectado el error hace falta indicar quien se encarga de tratarlo

Un manejador de excepciones tiene el siguiente formato:

El bloque try delimita el grupo de operaciones que puede producir excepciones

El bloque catch es el lugar al que se transfiere el control si alguna de las operaciones produce una excepción

En el ejemplo se ha usado un bloque try con su bloque catch para gestionar los errores del ejemplo anterior

Si alguna de las operaciones del bloque produce una excepción, se interrumpe el bloque try y se ejecuta el catch

Al finalizar este, se continua normalmente

Si no se produce ninguna excepción, el bloque catch se ignora

También existe la posibilidad de utilizar la excepción genérica Exception, pero es más recomendable usar el tipo de excepción específica para el error

En el ejemplo se ha usado un bloque try con su bloque catch para gestionar varias excepciones como en el ejemplo anterior

Un bloque try puede tener varios catch asociados

Cuando una excepción no se corresponde con ningún catch se propaga hacia atrás en la secuencia de invocaciones hasta encontrar un catch adecuado

En el ejemplo se gestionan las excepciones de los métodos f1 y f2 y si no encuentran ninguna continua la ejecución del código de forma normal fuera del bloque try

En este ejemplo se han tratado de mostrar las 3 alternativas que podemos usar para tratar la excepción IOException desde el método f2

Cuando se invoca un método que lanza excepciones es obligatorio:

  • que se maneje el error con un bloque catch

  • que se indique mediante throws su propagación

Bloque finally

Puede haber ocasiones en que se desea realizar alguna operación tanto si se producen excepciones como si no

Dichas operaciones se pueden situar dentro de un bloque finally

Un bloque finally tiene el siguiente formato:

Si no hay ninguna excepción se ejecutará el bloque try y el finally

En el ejemplo se ha controlado el cierre del archivo f en el bloque finaly, ejecutándose siempre

Si se produce alguna excepción:

  • Si es atrapada por un catch del mismo try se ejecuta este y luego el finally

    La ejecución continua después del finally normalmente

  • Si no es atrapada se ejecuta el finally y la excepción se propaga al contexto anterior

Jerarquía de las excepciones

Toda excepción debe ser una instancia de la clase de Throwable

De ella hereda los siguientes métodos:

  • getMessage()

    devuelve una cadena con un mensaje que detalla de detalla excepción

  • toString()

    devuelve una descripción breve que es el resultado es concatenar:

    • el nombre de la clase de este objeto
    • el token :
    • el resultado del método getLocalizedMessage() de este objeto
  • fillInStackTrace()

    registra información sobre el estado actual de los marcos de pila para el subproceso actual

    Si el estado de la pila no se puede escribir, no habrá valor devuelto

  • printStackTrace()

    devuelve la traza que ha seguido la excepción

    La primera línea de salida contiene el resultado del método toString() de este objeto

    Las líneas restantes representan los datos registrados previamente por el método fillInStackTrace()

La base de la jerarquía de excepciones de Java es:

  • Throwable

    • Error

    • Exception

      • RuntimeException

Las clases derivadas de Error describen errores internos de la JVM:

  • no deben ser lanzados por las clases de usuario

  • estas excepciones rara vez ocurren y cuando así sea lo único que se puede hacer es intentar cerrar el programa sin perder los datos

  • Ejemplos: OutOfMemoryError; StackOverflow; etc

Los programas en Java trabajarán con las excepciones de la rama Exception

Este grupo se divide a su vez en:

  • Las clases que derivan directamente de Exception (explícitas)

  • Las que derivan de RuntimeException (implícitas)

Se utilizan las RunTimeException para indicar un error de programación

Si se produce una excepción de este tipo hay que arreglar el código

Ejemplos:

  • Un cast incorrecto

  • Acceso a un array fuera de rango

  • Uso de un puntero null

El resto de Exception indican que ha ocurrido algún error debido a alguna causa ajena al programa

Ejemplos:

  • Un error de E/S

  • Error de conexión

Declaración de excepciones

Los métodos deben declarar sólo las excepciones explícitas

Las implícitas no deben declararse (aunque pueden producirse igualmente)

Por tanto cuando un método declara una excepción avisa de que puede producirse dicho error además de cualquier error implícito

Creación de excepciones

Si se necesita gestionar algún error no contemplado por los estándar que dispone Java, podemos crear nuestra propia clase de excepción

La única condición es que la clase derive de Throwable o de alguna que derive de ella

En la práctica generalmente se derivarán:

  • de RunTimeException si se desea notificar un error de programación

  • de Exception en cualquier otro caso

Resumen

Excepciones explícitas Excepciones implícitas
Derivan de Exception (no de RunTimeException) Derivan de RunTimeException
Indican un error externo a la aplicación Indican un error de programación
Si se lanzan es obligatorio declararlas No se declarar: se corrigen
Si se invoca un método que las lanza es obligatorio atraparlas o declararlas

Se pueden atrapar

En caso contrario, finaliza la aplicación

Excepciones y herencia

Al redefinir un método se está dando otra implementación para un mismo comportamiento

El nuevo método sólo podrá lanzar las excepciones declaradas en el método original

En el ejemplo se ha redefinido el método f de la clase A en la clase B con una excepción adicional

Un método puede declarar excepciones que no lance realmente

Así un método base puede permitir que las redefiniciones puedan producir excepciones

Los constructores, al no heredarse, pueden lanzar nuevas excepciones

Normas de uso

  1. Norma

    • Si una excepción se puede manejar no debe propagarse

    • Es más cómodo usar métodos que no produzcan errores

  2. Norma

    • No utilizar las excepciones para evitar una consulta

      • No abusar de ellas

  3. Norma

    • Separar el tratamiento de errores de la lógica

      Todo junto
      Separado
  4. Norma

    • No ignorar una excepción ya que dejamos el código con errores sin controlar