Java相当于CLR的UnhandledException事件

Dan*_*ker 2 java clr exception unhandled-exception

在CLR(C#,VB.NET等使用的运行时)中,有一种方法可以在抛出未处理的异常时注册要调用的回调.

Java中有类似的东西吗?

我猜它可能是一些API,你传递一个对象,用一个方法实现一些接口.抛出异常并且catch堆栈上没有匹配时,运行时将调用已注册对象上的方法,并将传递异常对象.

这将允许程序员保存堆栈跟踪.它还允许它们调用System.exit,以停止finally仅针对未处理的异常执行的块.

更新1.

为了说明这一点,这里有一个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");
}
Run Code Online (Sandbox Code Playgroud)

关键是通过调用Environment.FailFast(null)我可以阻止finally块执行.

果然,在Windows 7上运行的.NET 3.5和4.0中,我看不到输出中的"finally is execution"字符串.但是如果我注释掉这个FailFast调用,那么我确实在输出中看到了这个字符串.

更新2.

基于到目前为止的答案,这是我尝试用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");
}
Run Code Online (Sandbox Code Playgroud)

当我在Java 6(1.6.0_18)中运行它时,我看到:

  • 终于正在执行
  • 未捕获的异常

换句话说,JRE finally在执行未捕获异常处理程序之前执行块.

关于为什么这很重要的一些背景知识,这是一个更复杂的例子:

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...");
Run Code Online (Sandbox Code Playgroud)

所以有一个严重的错误,我希望我的程序停止并记录堆栈跟踪.但是在我能够做到这一点之前,finally堆栈中的某个地方有一个中间块(在一个真正的程序中它将是一个单独的方法)并且它试图访问文件系统.出了点问题.然后再往上一点,假设我抓到了,IOException因为它们对我来说不是什么大问题.

不用说,输出是:

  • 终于正在执行
  • 捕获了IOException
  • 程序一直在运行,好像什么也没发生过......

所以现在我偶然创造了一种情况,其中隐藏着严重的错误.

有两种解决方案:

  • 以某种方式确保finally永远不会抛出,因为它们无法在本地判断它是否安全.这是一种耻辱,因为它们完全可以抛出正常的执行路径,即当它们没有运行以响应先前的异常时.
  • 告诉运行时,finally当有未捕获的异常时,我不希望它运行块.

如果可以的话,后者肯定是我的选择.

Pét*_*rök 7

Thread.setUncaughtExceptionHandler().

更新:事实证明,"未处理/未捕获的异常"似乎意味着C#和Java略有不同.乍一看,您描述的行为(不幸的是)在Java中是正常的:

设置当此线程由于未捕获的异常而突然终止时调用的处理程序.

即,当异常已经从用户代码传播到线程中时,将调用未捕获的异常处理程序.这意味着它留下了包含finally块的方法,该方法已被正确执行.

AFAIK finally始终以Java运行,因此您的选项2不可行.

结论来自下面的讨论

选项1 - 不会在finally块中抛出任何东西- 虽然有限,但似乎是唯一真正的长期解决方案.

对于明显的日志记录部分,有一个选项3:

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");
}
Run Code Online (Sandbox Code Playgroud)