Gestión de Errores y Excepciones en Java

En Java, tanto Error como Exception son subclases de Throwable. Solo las instancias de Throwable pueden ser lanzadas (throw) o capturadas (catch), formando la base del mecanismo de manejo de excepciones.

Java distingue entre Exception y Error para clasificar diferentes tipos de situaciones anómalas:

  • Exception: Representa condiciones inesperadas que pueden ocurrir durante la ejecución normal del programa. Estas excepciones son predecibles y, a menudo, manejables mediante la captura y el tratamiento adecuado.
  • Error: Indica problemas graves y generalmente irrecuperables que ocurren en circunstancias excepcionales, a menudo relacionados con el entorno de ejecución o la máquina virtual (JVM). La mayoría de los Error provocan un estado inoperable e irrecuperable para el programa. Por su naturaleza, no se recomienda ni es práctico capturarlos. Ejemplos comunes incluyen OutOfMemoryError.

Las Exception se subdividen en dos categorías:

  • Excepciones comprobadas (Checked Exceptions): Estas deben ser explícitamente manejadas en el código fuente mediante bloques try-catch o declaradas en la firma del método (usando throws). El compilador de Java verifica su manejo.
  • Excepciones no comprobadas (Unchecked Exceptions): Conocidas también como excepciones de tiempo de ejecución (Runtime Exceptions), no son obligatorias de capturar en tiempo de compilación. Ejemplos típicos son NullPointerException y ArrayIndexOutOfBoundsException. Suelen ser el resultado de errores lógicos en el código que pueden ser prevenidos con una programación cuidadosa.

Relación jerárquica

Tanto Error como Exception heredan de Throwable. A su vez, RuntimeException es una subclase de Exception.

Error y RuntimeException (junto con sus subclases) se consideran excepciones no comprobadas (Unchecked Exceptions). Todas las demás excepciones son excepciones comprobadas (Checked Exceptions).

Diferencias clave

  • Error: Generalmente se relaciona con problemas a nivel de la máquina virtual, como fallos del sistema, errores de la JVM, falta de memoria o desbordamiento de la pila de llamadas. Ejemplos son java.lang.StackOverflowError y java.lang.OutOfMemoryError. El compilador no verifica su manejo. Se recomienda que las aplicaciones terminen ante estos errores, ya que son difíciles de rceuperar o prevenir desde el propio programa.
  • Exception: Representa condiciones que el programa puede y debe intentar manejar. Se deben capturar y procesar para intentar que la aplicación continúe su ejecución de forma controlada.

Principios fundamentales para el manejo de excepciones

  1. Capturar excepciones específicas: Evita capturar excepciones genéricas como Exception. En su lugar, captura las excepciones específicas que esperas y sabes cómo manejar. Por ejemplo, al usar Thread.sleep(), captura InterruptedException. Esto hace el código más legible y explícito, comunicando claramente la intención del manejo. Además, previene la captura accidental de excecpiones no deseadas, como RuntimeException, que podrían ser importantes para la depuración. A menos que se haya considerado cuidadosamente, evita capturar Throwable o Error, ya que puede ser difícil manejarlos adecuadamente (por ejemplo, un OutOfMemoryError).
  2. No ocultar (swallow) excepciones: Nunca ignores una excepción sin un manejo adecuado. Ocultar excepciones puede llevar a comportamientos impredecibles y a diagnósticos de problemas extremadamente difíciles. Asumir que un bloque de código no lanzará una excepción o que ignorarla es inofensivo es una práctica peligrosa, especialmente en código de producción. Si una excepción no se lanza o no se registra (por ejemplo, en un Logger), el programa puede terminar de forma incontrolada, y será muy complicado determinar el origen y la causa del fallo.

Ejemplos de errores comunes

java.lang.OutOfMemoryError

Ocurre cuando la JVM no puede asignar más memoria para un objeto porque no hay suficiente espacio libre en el heap.

Ejecutando el siguiente código con una restricción de heap de 150 MB (-Xmx150m) y solicitando 600 MB de memoria:


// Ejemplo de OutOfMemoryError
try {
    // Solicita 600MB de memoria
    byte[] memoriaGrande = new byte[1024 * 1024 * 600]; 
} catch (OutOfMemoryError e) {
    System.err.println("Error de memoria detectado: " + e.getMessage());
    e.printStackTrace();
}

El resultado será:


java.lang.OutOfMemoryError: Java heap space

java.lang.StackOverflowError

Se produce cuando la pila de llamadas de ejecución se desborda, típicamente debido a una recursión demasiado profunda o una recursión infinita.

Considera el siguiente código con una llamada recursiva infinita:


public class StackOverflowDemo {
    public static void main(String[] args) {
        metodoRecursivoProfundo();
    }
 
    public static void metodoRecursivoProfundo() {
        // Llamada recursiva infinita
        metodoRecursivoProfundo(); 
    }
}

La ejecución generará:


Exception in thread "main" java.lang.StackOverflowError

Otras excepciones comunes

  • ArrayIndexOutOfBoundsException: Intento de acceder a un índice de array fuera de sus límites válidos.
  • ArithmeticException: Ocurre durante una operación aritmética inválida, como la división por cero.
  • NullPointerException: Se lanza cuando se intenta usar una referencia a un objeto que es null.
  • IllegalArgumentException: Se lanza cuando un método recibe un argumento ilegal o inapropiado.

Etiquetas: java excepciones errores manejo de excepciones checked exceptions

Publicado el 6-22 00:06