Introducción: Por qué el manejo de errores es crítico para un desarrollador Java
Cualquier programa que vaya más allá de "Hello, World!" se enfrenta a situaciones imprevistas: el usuario ingresa letras en lugar de números, el archivo no se encuentra, la red no está disponible. En Java, para estos casos se ha desarrollado un mecanismo potente y elegante de excepciones (exceptions). Un manejo adecuado de errores no es simplemente "hacer la vista gorda ante el problema", sino crear un código robusto, predecible y seguro.
En este artículo, analizaremos no solo la construcción clásica try/catch, sino también técnicas avanzadas: try-with-resources, creación de excepciones propias y best practices que te ayudarán a escribir código profesional en Java.
1. Fundamentos: Jerarquía de excepciones y la construcción try/catch/finally
Antes de capturar errores, es necesario entender su naturaleza. En Java, todas las excepciones son herederas de la clase Throwable. Las ramas principales son Exception (excepciones que se pueden y deben manejar) y Error (errores críticos de la JVM que no tiene sentido manejar).
La división clave dentro de Exception es entre excepciones checked (verificadas) y unchecked (no verificadas).
- Checked exceptions (por ejemplo,
IOException,SQLException) — el compilador te obliga a manejarlas. Son fallos externos predecibles. - Unchecked exceptions (herederas de
RuntimeException:NullPointerException,ArrayIndexOutOfBoundsException) — son errores de lógica del programa. El compilador no exige su manejo, pero eso no significa que se puedan ignorar.
Construcción básica try-catch-finally
La forma más común de manejo es el bloque try, que contiene el código "peligroso", y uno o más bloques catch para interceptar tipos específicos de excepciones.
import java.io.*;
public class ReadFileExample { public static void main(String[] args) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("data.txt")); String line = reader.readLine(); System.out.println("Leído: " + line); } catch (FileNotFoundException e) { System.err.println("Error: ¡Archivo no encontrado! " + e.getMessage()); } catch (IOException e) { System.err.println("Error de entrada/salida: " + e.getMessage()); } finally { // finally se ejecuta SIEMPRE, incluso si hubo una excepción o un return try { if (reader != null) { reader.close(); // Es importante cerrar el recurso } } catch (IOException e) { System.err.println("Error al cerrar el archivo: " + e.getMessage()); } } }}
Importante: El bloque finally es necesario para la limpieza garantizada de recursos (cierre de archivos, conexiones a bases de datos). Sin embargo, a partir de Java 7, apareció una forma más elegante.
2. Enfoque moderno: try-with-resources (Java 7+)
Olvidar cerrar un archivo o una conexión es uno de los errores más comunes de los principiantes. La construcción try-with-resources cierra automáticamente todos los recursos que implementan la interfaz AutoCloseable (o Closeable). El código se vuelve más corto, limpio y seguro.
import java.io.*;
public class TryWithResourcesExample { public static void main(String[] args) { // Los recursos se declaran entre paréntesis después de try try (BufferedReader reader = new BufferedReader(new FileReader("data.txt")); BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
String line; while ((line = reader.readLine()) != null) {
```