Excepciones en Java
Introducción a las excepciones en Java: qué son, la jerarquía de excepciones y por qué importa el manejo de errores.
Una excepción es lo que ocurre cuando tu programa se encuentra con una situación que no puede manejar en su camino actual: un archivo que no existe, un número dividido entre cero, un índice de array fuera de rango. En lugar de devolver una respuesta incorrecta o corromper el estado de forma silenciosa, Java detiene el método actual, construye un objeto de excepción que describe lo que salió mal y comienza a buscar código que sepa cómo manejarlo. Aprender el mecanismo de excepciones es aprender cómo Java te indica qué salió mal, dónde y qué podrías hacer al respecto.
Qué es realmente una excepción
Una excepción es un objeto Java ordinario. Concretamente, una instancia de una clase que hereda de java.lang.Throwable. Cuando algo sale mal, la JVM (o tu propio código) crea uno de estos objetos y lo lanza. A partir de ese momento, el programa sigue un flujo de control diferente hasta que un bloque catch acepta la excepción o el hilo termina.
El objeto lleva información: un tipo (la clase — NullPointerException, IOException, etc.), un mensaje (una descripción legible por humanos) y un stack trace (la cadena de llamadas congelada en el momento en que se creó la excepción). Cuando lees una excepción en la consola, estás leyendo esas tres cosas.
Exception in thread "main" java.lang.ArithmeticException: / by zero
at calc.Money.divide(Money.java:42)
at calc.App.main(App.java:11)La primera línea es el tipo más el mensaje. Las líneas con sangría son el stack trace, con la llamada más reciente primero.
Por qué excepciones en lugar de códigos de error
Los lenguajes más antiguos — C es el ejemplo clásico — señalan los fallos con códigos de retorno: cada función devuelve un int, tú lo compruebas y, si es negativo, algo salió mal. Este enfoque tiene dos problemas:
- Puedes ignorar el valor de retorno. Un llamador que olvida comprobarlo no ve ningún fallo inmediato, y el error aparece más tarde en un lugar confuso.
- El camino del error ensucia el camino feliz. Cada línea de trabajo real está envuelta en
if (err) return err;.
Las excepciones invierten esto. El comportamiento por defecto es que una excepción no manejada detiene la ejecución, de forma ruidosa. Tú eliges manejarla donde realmente tienes una estrategia. El camino feliz se mantiene limpio; el camino de recuperación está en su propio bloque.
Las tres cosas que pueden salir mal
Java clasifica todo lo Throwable en tres categorías, y la diferencia importa porque el lenguaje las trata de forma distinta:
Error— la propia JVM tiene un problema grave.OutOfMemoryError,StackOverflowError. No los capturas en código normal. Generalmente no hay nada útil que puedas hacer.RuntimeException(una subclase deException) — errores de programación que aparecen en tiempo de ejecución.NullPointerException,IndexOutOfBoundsException,ClassCastException. El compilador no te obliga a manejarlos, porque en código correcto no deberían ocurrir.Exceptionverificada (todo lo demás bajoException) — fallos recuperables que el programa debería anticipar.IOException,SQLException. El compilador requiere que los captures o los declares en la cláusulathrowsde tu método.
La línea entre "error de programación" (excepción en tiempo de ejecución) y "fallo anticipado" (excepción verificada) es una de las decisiones de diseño de Java más debatidas. Volveremos a ello en excepciones verificadas vs. no verificadas en Java.
Cómo funcionan lanzar y capturar
Cuando se ejecuta un throw, la JVM:
- Deshace la pila — el método actual termina abruptamente, luego su llamador hace lo mismo, y así sucesivamente.
- En cada frame, comprueba si hay un bloque
try { ... } catch (SomeType e) { ... }cuyocatchcoincida con el tipo de la excepción (o un supertipo). - El primer
catchque coincide gana. El control salta allí, la pila deja de deshacerse y la ejecución continúa en el bloque catch. - Si nada coincide, el hilo muere. En un programa de un solo hilo, eso significa que la JVM imprime el stack trace y termina.
Por eso una excepción lanzada puede viajar a través de muchos métodos antes de ser capturada: cada lanzamiento no capturado sube un frame más.
Un primer vistazo
No tienes que escribir throw para encontrarte con una excepción — Java las lanza por sí mismo cuando algo sale mal. He aquí el ejemplo más simple: dividir un entero entre cero. La JVM crea una ArithmeticException por ti.
Sin el try/catch, la tercera iteración haría que todo el programa fallara y la cuarta nunca se ejecutaría. Con él, el fallo queda contenido: obtenemos un mensaje de error y el bucle continúa. Esa capacidad — limitar el daño de un fallo — es el objetivo del mecanismo de excepciones.
Qué cubre esta parte del libro
Los capítulos restantes de esta parte son el vocabulario de trabajo del manejo de excepciones en Java, una pieza a la vez:
- La forma de
try/catch/finallyy para qué sirve cada cláusula. - Múltiples catches y el atajo de multi-catch.
try-with-resourcespara todo lo que necesite cerrarse.- Lanzar excepciones tú mismo con
throwy declararlas conthrows. - Verificadas vs. no verificadas: cuál usar y cuándo.
- La jerarquía completa de clases.
- Cómo escribir tus propios tipos de excepción para tu dominio.
- Los principios que distinguen el buen manejo de excepciones del ruido defensivo.
Léelo en orden — cada capítulo asume el anterior.
Qué sigue
El manejo de excepciones comienza con la construcción más fundamental: el bloque try/catch. Continúa en Java try...catch.