Skip to content

9 UncaughtExceptionHandler

UncaughtExceptionHandler

Como sabemos, en general en la JVM se pueden producir dos tipos de excepciones:

  • Checked exceptions (excepciones comprobadas): Son aquellas que deben ser capturadas mediante try-catch o relanzadas incluyendo la cláusula throws en la declaración del método. Ejemplos de este tipo de excepciones son IOException o ClassNotFoundException.
  • Unchecked exceptions (excepciones no comprobadas): Son aquellas que NO es necesario capturar o relanzar, como por ejemplo NumberFormatException.

Cuando se genera una checked exception dentro del método run() de un hilo (o de un objeto que implemente Runnable), no tenemos más remedio que capturarla mediante try catch, ya que NO podemos redefinir el método run() añadiéndole la cláusula throws.

Por su parte, si se produce una unchecked exception dentro del método run() de un hilo, simplemente se mostrará el error en la consola y terminará la ejecución del programa.

Sin embargo, podemos modificar dicho comportamiento por defecto creando un objeto manejador (handler) que implemente la interfaz Thread.UncaughtExceptionHandler, y asignándoselo al hilo mediante el método setUncaughtExceptionHandler(handler) de la clase Thread.

@FunctionalInterface
public interface UncaughtExceptionHandler {
    void uncaughtException(Thread t, Throwable e);
}

De esta manera, cuando se produzca una uncaught exception dentro del método run() de dicho hilo, la JVM llamará al método uncaughtException() del objeto manejador, pasándole el objeto Thead y el objeto Exception para que decida cómo manejar la situación, evitando así la finalización automática de ejecución de la aplicación.

La clase Thead proporciona también el método estático Thread.setDefaultUncaughtExceptionHandler(handler) que permite establecer el objeto manejador cuyo método uncaughtException() debe ser llamado cuando se produzca una unchecked exception en cualquiera de los hilos del programa. De esta manera no será necesario indicar el manejador individualmente para cada hilo.

Así, en caso se producirse una unchecked exception dentro del método run() de un hilo, la JVM sigue el siguiente procedimiento:

  1. Llamará al método uncaughtException() del objeto manejador establecido individualmente para dicho hilo.
  2. Si no existe, llamará al método uncaughtException() del manejador establecido para el grupo de hilos al que pertenezca el hilo (ThreadGroup, lo veremos más adelante).
  3. Si no existe, llamará al del manejador por defecto establecido para la aplicación,
  4. Si ninguno de los anteriores existe, mostrará el error en la consola y finalizará la ejecución de la aplicación.

Proyecto UncaughtExceptionHandler

En este proyecto crearemos un programa que a conciencia produce una unchecked exception en un hilo, para que sea manejada por un objeto UncaughtExceptionHandler que será asociado al mismo.

public class Main {

    public static void main(String[] args) {
        Thread thread = new Thread(new Task());
        thread.setUncaughtExceptionHandler(new ExceptionHandler());
        thread.start();
    }

}
import java.lang.Thread.UncaughtExceptionHandler;

public class ExceptionHandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.printf("Thread: %s\n", t.getId());
        System.out.printf("Exception: %s: %s\n", e.getClass().getName(), e.getMessage());
        System.out.printf("Stack Trace: \n");
        e.printStackTrace(System.out);
    }

}
public class Task implements Runnable {

    @Override
    public void run() {
        // Throws a checked exception.
        int num = Integer.parseInt("Baldomero");
        // It will never be executed.
        System.out.printf("Number: %d ", num);
    }

}

Si ejecutamos el programa veremos que se captura la excepción y se muestran datos sobre ella