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:
- Envolverlo en un
try-catch(Arreglarlo). - Añadir
throwsa 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
Exceptionpero NO deRuntimeException. - 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 untry-catchcada vez que usas un objeto por si esnull, porque el código sería ilegible. Se asume que, como programador, has comprobado que no sea null antes.
Tabla comparativa
| Tipo | Checked (Verificada) | Unchecked (Runtime) | Error |
|---|---|---|---|
| Clase Base | Exception | RuntimeException | Error |
| Origen | Factores externos (Red, IO). | Lógica del programador (Bugs). | Entorno JVM crítico. |
| Compilador | Te obliga a gestionarlas. | Te ignora. | Te ignora. |
| Ejemplos | IOException, SQLException. | NullPointer, IndexOutOfBounds. | OutOfMemoryError. |
| Acción | Recuperarse (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);
}
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...");
}
}
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"));
}