在 CLR(C#、VB.NET 等使用的运行时)中,有一种方法可以注册回调,以便在引发未处理的异常时调用。
Java中有类似的东西吗?
我猜想它可能是某个 API,您可以将一个对象传递给该 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");
}
关键是通过调用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");
}
当我在 Java 6 (1.6.0_18) 中运行它时,我看到:
- finally 正在执行
- 未捕获的异常
换句话说,JREfinally
在执行未捕获异常处理程序之前执行块。
关于为什么这很重要的一些背景,这里有一个更复杂的例子:
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
块(在一个真正的程序中它会在一个单独的方法中),它会尝试访问文件系统。出了点问题。然后再往上一点假设我有一个问题,IOException
因为它们对我来说没什么大不了的。
不用说,输出是:
- finally 正在执行
- 捕获 IOException
- 程序继续运行,就好像什么都没发生过一样……
所以现在我无意中创造了一个严重的错误对我隐藏的情况。
有两种解决方案:
- 以某种方式确保
finally
块永远不会抛出,因为它们无法在本地判断它是否安全。这是一种耻辱,因为它们完全可以在正常执行路径上抛出,即当它们没有运行以响应先前的异常时。 - 告诉运行时我不希望它
finally
在有未捕获的异常时运行块。
如果可以的话,后者当然是我的首选。