TutorJava Nivel Básico: tutorial completo Java 21

Las excepciones son el mecanismo de Java para gestionar errores y situaciones excepcionales. Un buen manejo de excepciones hace el código más robusto y más fácil de depurar.

Jerarquía de excepciones

Todas las excepciones heredan de Throwable. Hay dos ramas principales:

  • Error: problemas graves de la JVM (OutOfMemoryError, StackOverflowError). No se deben capturar en código de aplicación.
  • Exception: situaciones que el código puede manejar.
    • Checked (comprobadas en compilación): heredan de Exception pero no de RuntimeException. El compilador obliga a capturarlas o declararlas con throws. Ejemplo: IOException, SQLException.
    • Unchecked (no comprobadas): heredan de RuntimeException. Indican errores de programación. Ejemplo: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException.

try / catch / finally

public int dividir(int a, int b) {
    try {
        return a / b;
    } catch (ArithmeticException e) {
        System.err.println("División por cero: " + e.getMessage());
        return 0;
    } finally {
        // Siempre se ejecuta, haya o no excepción
        System.out.println("Operación finalizada.");
    }
}

Se pueden capturar múltiples tipos en un solo catch (Java 7+):

try {
    // código que puede lanzar varias excepciones
} catch (IOException | SQLException e) {
    System.err.println("Error de I/O o BD: " + e.getMessage());
}

try-with-resources (Java 7+)

Cualquier objeto que implemente AutoCloseable se cierra automáticamente al salir del bloque try, incluso si hay excepción. Elimina la necesidad de cerrar recursos manualmente en el finally:

// Sin try-with-resources (propenso a resource leaks)
BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader("fichero.txt"));
    String linea = br.readLine();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (br != null) try { br.close(); } catch (IOException e) {}
}

// Con try-with-resources (limpio y seguro)
try (var br = new BufferedReader(new FileReader("fichero.txt"))) {
    String linea = br.readLine();
    System.out.println(linea);
} catch (IOException e) {
    System.err.println("Error leyendo fichero: " + e.getMessage());
}

Lanzar excepciones: throw y throws

public void setEdad(int edad) {
    if (edad < 0 || edad > 150) {
        throw new IllegalArgumentException("Edad inválida: " + edad);
    }
    this.edad = edad;
}

// Declarar checked exception en la firma
public String leerFichero(String ruta) throws IOException {
    return Files.readString(Path.of(ruta));
}

Excepciones personalizadas

// Excepción de negocio (unchecked)
public class SaldoInsuficienteException extends RuntimeException {
    private final double saldoActual;
    private final double importeSolicitado;

    public SaldoInsuficienteException(double saldoActual, double importeSolicitado) {
        super(String.format("Saldo insuficiente: tiene %.2f, necesita %.2f",
              saldoActual, importeSolicitado));
        this.saldoActual = saldoActual;
        this.importeSolicitado = importeSolicitado;
    }

    public double getSaldoActual() { return saldoActual; }
    public double getImporteSolicitado() { return importeSolicitado; }
}

// Uso
public void retirar(double importe) {
    if (importe > saldo) {
        throw new SaldoInsuficienteException(saldo, importe);
    }
    saldo -= importe;
}

Buenas prácticas

  • Captura la excepción más específica posible, no Exception genérica.
  • Nunca captures y silencies: catch (Exception e) {} es un antipatrón.
  • Usa excepciones unchecked (RuntimeException) para errores de programación y de negocio. Las checked son para condiciones recuperables externas (fichero no encontrado, red caída).
  • Incluye información útil en el mensaje: qué ocurrió, con qué valor, dónde.
  • Cierra siempre los recursos con try-with-resources.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP