Resumen del Tema 7: Control y Manejo de Excepciones
En el desarrollo de software, es inevitable que ocurran errores. Una excepción es un evento producido durante la ejecución de un programa que altera el flujo normal de las instrucciones. Antes, los programadores tenían que devolver tediosos códigos de error (como "-1" o "404") en cada método; hoy en día, Java nos ofrece un sistema robusto orientado a objetos para capturar y manejar estos problemas.
1. Jerarquía de Excepciones
En Java, todos los errores y excepciones derivan de la clase base java.lang.Object, pasando por Throwable, la cual se divide en dos grandes ramas:
- Error (Irrecuperables): Son errores graves del entorno o de la Máquina Virtual de Java (JVM) que no debemos intentar gestionar en nuestro código. Ejemplos:
StackOverflowErroroOutOfMemoryError. - Exception (Recuperables): Son los problemas derivados de nuestro código o del uso de la aplicación, y son los que sí debemos capturar y gestionar.
2. Excepciones: Checked vs Unchecked
Dentro de la rama Exception, encontramos dos clasificaciones vitales a la hora de programar:
| Checked (Verificadas) | Unchecked (No Verificadas) |
|---|---|
| Dependen del uso del programa (ej: el usuario introduce mal la ruta de un archivo). | Son errores de programación nuestros (ej: acceder a un índice de array que no existe). |
| El compilador obliga a gestionarlas (capturarlas o propagarlas). | Java las lanza automáticamente. No estamos obligados a gestionarlas mediante código, debemos arreglar el bug. |
Heredan de Exception.Ej: IOException, FileNotFoundException. |
Heredan de RuntimeException.Ej: NullPointerException, ArithmeticException. |
3. Manejo de Excepciones: Try, Catch, Finally
Cuando un bloque de código es susceptible de generar una excepción, podemos rodearlo con una estructura try-catch. Esto evita que el programa se cuelgue bruscamente.
try: Contiene el código que puede fallar.catch: Captura la excepción específica y define cómo actuar ante ella. Se pueden encadenar varios.finally: (Opcional) Código que se ejecutará siempre, haya ocurrido un error o no. Es ideal para cerrar conexiones o liberar recursos.
System.out.println("COMIENZO PROGRAMA DIVISIÓN");
try {
int dividendo = 5;
int divisor = 0;
// Esto lanzará ArithmeticException
System.out.println("Resultado: " + (dividendo / divisor));
} catch (ArithmeticException ex) {
System.out.println("Error: Imposible dividir por 0.");
} finally {
System.out.println("Operación finalizada.");
}
System.out.println("FIN PROGRAMA");
4. Propagación y Lanzamiento (Throws y Throw)
A veces, el método donde ocurre el error no es el responsable de decidir qué hacer. En esos casos, podemos propagar la excepción hacia el método que lo invocó utilizando throws en la firma del método.
// El método "avisa" de que puede lanzar esta excepción
private static int division(int dividendo, int divisor) throws ArithmeticException {
return dividendo / divisor;
}
Además, podemos lanzar manualmente una excepción cuando se incumpla una regla de negocio utilizando la palabra throw:
public void setEdad(int edad) {
if (edad < 0) {
throw new IllegalArgumentException("La edad no puede ser negativa.");
}
this.edad = edad;
}
5. Excepciones Personalizadas
Podemos crear nuestras propias excepciones ad-hoc para hacer nuestro código más semántico. Basta con crear una clase que herede de Exception (si queremos que sea Checked) o de RuntimeException / IllegalArgumentException (si queremos que sea Unchecked).
public class ExcepcionEdadInvalida extends IllegalArgumentException {
public ExcepcionEdadInvalida(String mensaje) {
super(mensaje);
}
}
6. Buenas Prácticas y Aserciones
- Nunca ocultar excepciones: Evita hacer un bloque
catchvacío. Si ignoras el error, será muy difícil depurar el programa después. - Capturar lo antes posible: Atrapa la excepción en el nivel más bajo posible para poder recomponer la ejecución del programa rápidamente.
- Sé específico: Evita capturar la clase genérica
Exception, captura las excepciones concretas (comoIOException). - Aserciones (assert): Sirven para comprobar condiciones durante la etapa de desarrollo (por ejemplo:
assert x > 0 : "El valor debe ser positivo";). No deben usarse en producción como sustitutos del control de errores normal.