在Java 7中,该特性被添加到(通过getSuppressed()
)从try-with-resources语句的隐式finally块抛出的get异常。
似乎仍然没有一种方法(据我所知)做相反的事情-当有一个显式的finally块并抛出异常时,掩盖了从try/catch抛出和挂起的异常。
为什么Java不提供通过类似于getSuppressed()
的机制来获得这些隐藏/丢失异常的功能?
似乎这个功能的实现将类似于getSuppressed()
或链式异常中使用的,并且提供的好处将非常有用,但它继续在每个版本中被遗漏。
通过类似于getSuppressed()
的方法调用使这些被屏蔽的异常对程序员可用会有什么危险?
(如果这个功能已经存在,我只是无能为力,提前道歉。)
抑制功能不限于使用资源进行尝试,您可以在类似的情况下使用它。例如,它是为其他情况提供的。
try-with-resources将关闭资源的逻辑置于幕后,因此您无法在自己的代码中直接访问处理过程中发生的任何异常。所以他们添加了"抑制"的东西,这样他们就可以在幕后代码中使用它。
但聪明的是,他们没有只是让它可以在那里使用。你可以自己使用,通过Throwable#addSuppressed
。
你可以在JLS§14.20.3.1给出的伪代码示例中看到这一点;下面是它的真实代码版本:
{
SomeResource someResource = null;
Throwable primaryException = null;
try {
someResource = /*...get the resource...*/;
/*...do something...*/
}
catch (Throwable t) {
primaryException = t;
throw t;
}
finally {
if (someResource != null) {
if (primaryException != null) {
// Dealing with a primary exception, close the resource
// and suppress any exception resulting
try {
someResource.close();
}
catch (Throwable suppressed) {
primaryException.addSuppressed(suppressed);
}
}
else {
// Not dealing with a primary exception, close the
// resource without suppressing any resulting exception
someResource.close();
}
}
}
}
注意不同的行为(在try中使用异常A,在finally中使用异常B):
在try-with-resources
异常中a抑制异常b
在正常的try
异常中,B屏蔽了异常a。
如果你想要向后兼容(你总是想要它),你需要让B抑制a,但这与try-with-resources
的作用完全相反(实际上,与大多数开发人员想要的相反)。
作为一种解决方案,您可以使用Oracle博客中关于try-with-resources
如何工作的(稍微修改)代码:
Exception ex;
try {
doWork();
} catch (Exception e) {
ex = e;
throw(e);
} finally {
try {
doFinally();
} catch (Exception e) {
if (ex != null) {
ex.addSuppressed(e);
} else {
throw(e);
}
}
}
如果你想让finally异常抑制初始异常,显然要把throw移出初始catch。