(用户soc)对关于尾调用优化的问题的回答提到Java 7 有一个称为“抑制异常”的新功能,因为“添加了 ARM”(支持 ARM CPU?)。
在这种情况下,什么是“被抑制的异常”?在其他情况下,“被抑制的异常”将是一个被捕获然后被忽略的异常(很少是一个好主意);这显然是不同的东西。
(用户soc)对关于尾调用优化的问题的回答提到Java 7 有一个称为“抑制异常”的新功能,因为“添加了 ARM”(支持 ARM CPU?)。
在这种情况下,什么是“被抑制的异常”?在其他情况下,“被抑制的异常”将是一个被捕获然后被忽略的异常(很少是一个好主意);这显然是不同的东西。
为了澄清 Jon 的回答中的引用,一个方法(每次执行)只能抛出一个异常,但在 a 的情况下,可能try-with-resources
会抛出多个异常。例如,可能会在块中抛出一个,而另一个可能会finally
从try-with-resources
.
编译器必须确定“真正”抛出哪些。它选择抛出在显式代码(块中的代码)中引发的try
异常,而不是由隐式代码(finally
块)抛出的异常。因此,隐式块中抛出的异常被抑制(忽略)。这只发生在多个异常的情况下。
我相信评论者所指的是一个异常,当它在try-with-resourcesfinally
块的隐式块内抛出时,在从块中抛出现有异常的上下文中时,它会被半忽略:try
可以从与 try-with-resources 语句关联的代码块中引发异常。在示例 writeToFileZipFileContents 中,可以从 try 块中引发异常,并且当 try-with-resources 语句尝试关闭 ZipFile 和 BufferedWriter 对象时,最多可以引发两个异常。如果从 try 块中抛出一个异常,并且从 try-with-resources 语句中抛出一个或多个异常,则从 try-with-resources 语句中抛出的那些异常将被抑制,并且该块抛出的异常就是那个由 writeToFileZipFileContents 方法抛出。您可以通过从 try 块抛出的异常调用 Throwable.getSuppressed 方法来检索这些抑制的异常。
(这是引用链接页面中名为“Suppressed Exceptions”的部分。)
Java7之前;代码中抛出了异常,但不知何故被忽略了。
例如)
public class SuppressedExceptions {
public static void main(String[] args) throws Exception {
try {
callTryFinallyBlock();
} catch (Exception e) {
e.printStackTrace(); **//Only Finally Exception is Caught**
}
}
private static void callTryFinallyBlock() throws Exception {
try
{
throw new TryException(); **//This is lost**
}
finally
{
FinallyException fEx = new FinallyException();
throw fEx;
}
}
}
class TryException extends Exception {
}
class FinallyException extends Exception {
}
在 JDK 7 的 Throwable 类中添加了一个新的构造函数和两个新方法。如下所示:
Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);
使用这种新方法,我们也可以处理那些被抑制的异常。
public class SuppressedExceptions {
public static void main(String[] args) throws Exception {
try {
callTryFinallyBlock();
} catch (Exception e) {
e.printStackTrace();
for(Throwable t: e.getSuppressed())
{
t.printStackTrace();
}
}
}
private static void callTryFinallyBlock() throws Exception {
Throwable t = null;
try
{
throw new TryException();
}
catch (Exception e) {
t = e;
}
finally
{
FinallyException fEx = new FinallyException();
if(t != null)fEx.addSuppressed(t);
throw fEx;
}
}
}
class TryException extends Exception {
}
class FinallyException extends Exception {
}
在 Java7 中尝试使用资源;默认情况下,AutoCloseable::close() 处的异常与 try 异常一起添加为抑制异常。
还要注意这与链式异常不同(JDK 1.4 引入的,旨在使轻松跟踪异常之间的因果关系成为可能。)
承认以下代码:
public class MultipleExceptionsExample {
static class IOManip implements Closeable{
@Override
public void close() {
throw new RuntimeException("from IOManip.close");
}
}
public static void main(String[] args) {
try(IOManip ioManip = new IOManip()){
throw new RuntimeException("from try!");
}catch(Exception e){
throw new RuntimeException("from catch!");
}finally{
throw new RuntimeException("from finally!");
}
}
}
使用所有行,您将获得:java.lang.RuntimeException: from finally!
删除finally
块你会得到:java.lang.RuntimeException: from catch!
删除catch
块你会得到:
Exception in thread "main" java.lang.RuntimeException: from try!
Suppressed: java.lang.RuntimeException: from IOManip.close
抑制的异常是资源关闭时在 try-with-resources 语句(Java 7 中引入)中发生的附加异常。AutoCloseable
因为关闭AutoCloseable
资源时可能会发生多个异常,所以附加异常作为抑制异常附加到主要异常。
查看一段 try-with-resources 示例代码的字节码,标准JVM 异常处理程序用于适应 try-with-resources 语义。
ARM - 自动资源管理(从 Java 7 开始引入)
举一个非常简单的例子
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
现在,如果readLine()
函数抛出异常,然后甚至close()
函数 [in finally 块] 抛出异常,则后者被赋予更高的优先级并被抛出回调用函数。在这种情况下Exception thrown by the readLine() method is ignored/suppressed
。您可以在异常中链接导致异常并从 finally 块中重新抛出异常。
由于java 7
提供了检索抑制异常的功能。public final java.lang.Throwable[] getSuppressed()
您可以在捕获的可抛出对象上调用函数来查看抑制的异常。
例如。
static String readFirstLineFromFileWithFinallyBlock(String path)
throws Exception {
try (BufferedReader br = new BufferedReader(new FileReader(path));) {
return br.readLine();
}
}
现在,如果在关闭资源时抛出了br.readLine();
行Exception1
,然后让我们说Exception2
被抛出[想象这发生在 try-with-resource 语句创建的隐式 finally 块中],那么 Exception1 会抑制 Exception2。
这里有几点需要注意——
我在下面的帖子中使用代码片段和输出编译了大多数可能的场景。
希望有帮助。
您也可以在 Java 6 中抑制异常(涉及一些小技巧),
我创建了一个在 Java 1.6 和 Java 1.7 中透明地处理抑制异常的实用程序。你可以在这里找到实现
您只需拨打以下电话:
public static <T extends Throwable> T suppress(final T t, final Throwable suppressed)
抑制异常,以及
public static Throwable [] getSuppressed(final Throwable t) {
获取异常的抑制异常,以防有人仍在使用 Java 1.6
我认为这与“链式异常设施”有关。随着堆栈跟踪的发展,它将影响该设施如何处理异常。随着时间的推移,作为一组链接异常的一部分的异常可以被抑制。查看Throwable 文档了解更多详细信息。