Java 相当于 CLR 的 UnhandledException 事件

标签 java clr exception unhandled-exception

在 CLR(C#、VB.NET 等使用的运行时)中,有一种方法可以注册回调,以便在引发未处理的异常时调用该回调。

Java中有类似的东西吗?

我猜测它可能是一些 API,您可以将一个对象传递给该 API,该对象使用单个方法实现某个接口(interface)。当抛出异常并且堆栈上没有匹配的 catch 时,运行时将调用注册对象上的方法,并传递异常对象。

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

更新 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");
}

重点是,通过调用 Environment.FailFast(null) 我可以停止 finally block 的执行。

果然,在 Windows 7 上运行的 NET 3.5 和 4.0 中,我在输出中没有看到“finally isexecution”字符串。但是,如果我注释掉 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");
}

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

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

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

有关为什么这很重要的一些背景信息,这里有一个更复杂的示例:

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...");

所以存在严重的错误,我希望我的程序停止并记录堆栈跟踪。但在我执行此操作之前,堆栈上的某个位置有一个中间 finally block (在实际程序中,它将位于单独的方法中),并且它会尝试访问文件系统。出了问题。然后再往上一点,假设我捕获了 IOException,因为它们对我来说没什么大不了的。

不用说,输出是:

  • 终于执行
  • 捕获 IOException
  • 程序继续运行,就像什么都没发生一样...

所以现在我不小心造成了一种情况,其中严重的错误对我来说是隐藏的。

有两种解决方案:

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

如果可以的话,后者当然是我的首选。

最佳答案

参见 Thread.setUncaughtExceptionHandler() .

更新:事实证明,“未处理/未捕获的异常”在 C# 和 Java 中的含义似乎略有不同。乍一看,您描述的行为在 Java 中似乎是正常的(对您来说不幸的是):

Set the handler invoked when this thread abruptly terminates due to an uncaught exception.

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

据我所知finally block 总是在Java中运行,因此您的选项2不可行。

下面讨论的结论

选项 1 - 不向 finally 中扔任何东西 block - 尽管有限制,但似乎是唯一真正的长期解决方案。

对于日志记录部分,有一个选项 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");
}

<罢工>

关于Java 相当于 CLR 的 UnhandledException 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3086125/

相关文章:

java - 捕获异常并重新抛出它,但它不是异常

java - 尝试在空对象引用上调用接口(interface)方法 'boolean java.util.Set.addAll(java.util.Collection)'

java - 在一个方法中处理多个异常

java - 模拟正在测试的同一类中的 void 方法

Java StreamCorruptedException

java - 如何在 Java Swing 中关闭 PrinterJob 对话框?

java - TicTacToe Java - 检查获胜者

java - 平台到底是什么意思?有多少个版本的 CLR 和 JVM 可用?

c# - ValueType.ToString 和 ReferenceType.ToString 的区别

.net - CLR JIT 优化违反了因果关系?