Pregunta

En el CLR (el tiempo de ejecución utilizado por C #, VB.NET, etc) hay una manera de registrar una devolución de llamada que se llamará cuando se produce una excepción no controlada.

¿Hay algo similar en Java?

supongo que sería presumiblemente alguna API para la que desee pasar un objeto que implementa alguna de las interfaces con un solo método. Cuando se produce una excepción y no hay catch coincidente en la pila, el tiempo de ejecución sería llamar al método en el objeto registrado, y sería pasado el objeto de excepción.

Esto permitiría que el programador para guardar el seguimiento de la pila. También permitiría que llamen System.exit, a los bloques finally dejan de ejecutarse sólo para las excepciones no controladas.

Actualización 1.

Para ilustrar esto, aquí es una muestra en C #:

// register custom handler for unhandled exceptions
AppDomain.CurrentDomain.UnhandledException += (sender, evt) =>
{
    Console.WriteLine("unhandled exception");
    Environment.FailFast(null);
};

try
{
    throw new NullReferenceException();
}
finally
{
    Console.WriteLine("finally is executing");
}

El punto es que al poner en la llamada a Environment.FailFast(null) puedo parar el bloque finally de ejecución.

Efectivamente, en NET 3.5 y 4.0 que se ejecuta en Windows 7, no veo la "finalmente está ejecutando" cadena en la salida. Pero si comento hacia fuera la llamada FailFast, entonces lo hago ver que la cadena en la salida.

Actualización 2.

Sobre la base de las respuestas hasta el momento, aquí está mi intento de reproducir esto en Java.

// register custom handler for unhandled exceptions
Thread.currentThread().setUncaughtExceptionHandler(

    new Thread.UncaughtExceptionHandler() {

        public void uncaughtException(
                final Thread t, final Throwable e) {

            System.out.println("Uncaught exception");
            System.exit(0);
        }
    }
);

try
{
    throw new NullPointerException();
}
finally
{
    System.out.println("finally is executing");
}

Cuando corro que en Java 6 (1.6.0_18) Veo:

  • finalmente está ejecutando
  • excepción no detectada

En otras palabras, el JRE ejecuta bloques finally antes de ejecutar el manejador no detectada-excepción.

Para algunos antecedentes sobre por qué esto es importante, aquí hay un ejemplo más complejo:

try
{
    try
    {
        throw new NullPointerException();
    }
    finally
    {
        System.out.println("finally is executing");
        throw new java.io.IOException();
    }
}
catch (java.io.IOException x)
{
    System.out.println("caught IOException");
}

System.out.println("program keeps running as if nothing had happened...");

Así que hay un grave error y quiero mi programa para detener y registrar el seguimiento de la pila. Pero antes de que pueda hacer esto, hay un intermedio en algún bloque de finally en la pila (en un programa real de lo que sería en un método separado) y trata de acceder al sistema de archivos. Algo va mal. A continuación, un poco más arriba en la pila supongamos que tengo una captura de IOException porque no son un gran problema para mí.

No hace falta decir, la salida es:

  • finalmente está ejecutando
  • atrapados IOException
  • programa sigue funcionando como si nada hubiera sucedido ...

Así que ahora tengo por accidente creado una situación en la que los errores graves se ocultan de mí.

Hay dos soluciones:

  • alguna manera asegurar que los bloques finally no tiro, porque no pueden decir a nivel local si es seguro. Esto es una lástima, porque es perfectamente bien que ellos arrojan sobre la ruta de ejecución normal, es decir, cuando no se están ejecutando en respuesta a una excepción anterior.
  • decirle al tiempo de ejecución que no quiero que se ejecute bloques finally cuando hay una excepción no capturada.

Este último es sin duda mi preferencia si está disponible.

¿Fue útil?

Solución

Consulte Thread.setUncaughtExceptionHandler() .

Actualización: como se vio después, la "excepción no controlada / no detectada" parece significar cosas ligeramente diferentes en C # y Java. A primera vista, el comportamiento que usted describe parece ser (por desgracia para usted) normales en Java:

  

Set el manejador invoca cuando este subproceso termina abruptamente debido a una excepción no capturada.

es decir. controlador de excepciones se llama cuando la excepción ya se ha propagado fuera del código de usuario, hasta en la rosca. Esto implica que dejó el método que contiene el bloque finally, que ha sido debidamente ejecutado.

bloques finally yo sepa son siempre ejecutar en Java, por lo que su opción 2 no es viable.

Conclusión de la discusión a continuación

Opción 1 - No tirar nada en bloques finally -., A pesar de la limitación, parece ser la única solución real a largo plazo

Para claridad la parte de registro, hay una opción 3 embargo:

try
{
    try
    {
        throw new NullPointerException();
    }
    catch (Exception x)
    {
        System.out.println("caught Exception" + x.getMessage());
        x.printStackTrace();
        throw x; // keep original behaviour
    }
    finally
    {
        System.out.println("finally is executing");
        throw new java.io.IOException();
    }
}
catch (java.io.IOException x)
{
    System.out.println("caught IOException");
}

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top