java-excepciones-concepto-checked-unchecked

Excepciones en Java: jerarquía, checked y unchecked

  • 4 min

Una excepción es un objeto que representa una situación anómala y altera el flujo normal del programa.

Hasta ahora, hemos programado pensando sobre todo en el camino correcto: que el archivo existe, el usuario introduce datos válidos y la red responde. Pero la realidad es cruel. El software falla.

En Java, cuando algo interrumpe el flujo normal de ejecución, se lanza una Excepción. Si no la capturamos, el programa explota (crashea) y muestra el temido Stack Trace (esa pared de texto rojo en la consola).

Hoy vamos a entender la arquitectura de errores de Java, porque tiene una peculiaridad que no tiene ningún otro lenguaje moderno: la distinción entre errores que estás obligado a capturar y los que no.

La jerarquía Throwable

En Java, un error no es un código numérico (como en C). Un error es un Objeto. Todos los errores descienden de la clase madre java.lang.Throwable. De ella cuelgan dos ramas principales con filosofías muy distintas.

Rama 1: Error

Representan problemas graves de la Máquina Virtual (JVM). Son situaciones de las que es imposible recuperarse.

  • Ejemplos: OutOfMemoryError (te has quedado sin RAM), StackOverflowError (bucle infinito recursivo).

Importante: En código de aplicación, normalmente no debes capturar Error. Representa problemas graves de la JVM o del entorno que rara vez pueden recuperarse de forma segura.

Rama 2: Exception

Aquí es donde trabajamos nosotros. Representan errores del programa o de factores externos (ficheros, bases de datos) de los que sí podríamos recuperarnos.

  • Ejemplos: IOException, NullPointerException, SQLException.

El gran debate: checked vs unchecked

Dentro de la rama Exception, Java hace una distinción que define la personalidad del lenguaje.

Checked exceptions (verificadas)

Son excepciones que el Compilador te OBLIGA a gestionar.

Si utilizas un método que lanza una Checked Exception, el código no compilará a menos que hagas una de estas dos cosas:

  1. Envolverlo en un try-catch (Arreglarlo).
  2. Añadir throws a tu método (Pasarle el marrón al que te ha llamado).

Java asume que son errores “previsibles” y quiere asegurarse de que no se te olviden.

  • ¿Cuáles son? Cualquier clase que herede de Exception pero NO de RuntimeException.
  • Ejemplo: FileNotFoundException. Si intentas abrir un fichero, Java te grita: “¡Oye! ¿Y si el fichero no está? ¡Dime qué hago!”.

Unchecked exceptions (no verificadas)

Son excepciones que ocurren en tiempo de ejecución y el compilador no te avisa. No estás obligado a capturarlas (aunque deberías evitar que ocurran).

Suelen representar fallos de programación (bugs) o errores lógicos.

  • ¿Cuáles son? Todas las que heredan de RuntimeException.
  • Ejemplo: NullPointerException. Java no te obliga a poner un try-catch cada vez que usas un objeto por si es null, porque el código sería ilegible. Se asume que, como programador, has comprobado que no sea null antes.

Tabla comparativa

TipoChecked (Verificada)Unchecked (Runtime)Error
Clase BaseExceptionRuntimeExceptionError
OrigenFactores externos (Red, IO).Lógica del programador (Bugs).Entorno JVM crítico.
CompiladorTe obliga a gestionarlas.Te ignora.Te ignora.
EjemplosIOException, SQLException.NullPointer, IndexOutOfBounds.OutOfMemoryError.
AcciónRecuperarse (reintentar, avisar).Corregir el código (el bug).Reiniciar la app.

El principio “handle or declare”

Cuando te enfrentas a una Checked Exception, tienes que tomar una decisión de diseño.

Imagina un método que lee un fichero:

import java.io.FileReader;
import java.io.File;

public void leerFichero() {
    File f = new File("notas.txt");
    // La siguiente línea marca ERROR DE COMPILACIÓN
    // FileReader lanza FileNotFoundException (Checked)
    FileReader fr = new FileReader(f);
}
Copied!

Tienes dos opciones:

Opción A: Handle (Gestionar) Usar try-catch para solucionar el problema ahí mismo.

public void leerFichero() {
    try {
        FileReader fr = new FileReader(new File("notas.txt"));
    } catch (FileNotFoundException e) {
        System.out.println("El fichero no existe. Creando uno nuevo...");
    }
}
Copied!

Opción B: Declare (Declarar) Lavarte las manos y decir que tu método puede fallar. Quien llame a tu método tendrá que ocuparse.

// Añadimos 'throws' a la firma
public void leerFichero() throws FileNotFoundException {
    FileReader fr = new FileReader(new File("notas.txt"));
}
Copied!