什么是抑制的exception?

一个关于tail call优化问题的回答 (由用户soc )提到,由于“增加了ARM”(支持ARM CPU?),Java 7有一个称为“抑制exception”的新function。

在这种情况下什么是“压制例外”? 在其他情况下,“被压制的例外”将是一个被抓住然后被忽视的例外(很less是一个好主意)。 这显然是不同的。

我相信评论者指的是在try-with-resources块的隐式finally块内抛出的exception,在从try块抛出现有exception的上下文中被抛出:

可以从与try-with-resources语句相关联的代码块中抛出exception。 在示例writeToFileZipFileContents中,可以从try块抛出一个exception,当试图closuresZipFile和BufferedWriter对象时,最多可以从try-with-resources语句中抛出两个exception。 如果从try块抛出一个exception,并且从try-with-resources语句抛出一个或多个exception,那么从try-with-resources语句抛出的exception就会被取消,而由块抛出的exception是这是由writeToFileZipFileContents方法引发的。 您可以通过从try块引发的exception中调用Throwable.getSuppressed方法来检索这些抑制的exception。

(这是从链接页面引用一个名为“Suppressed Exceptions”的部分)。

为了澄清Jon的答案中的引用,只有一个exception可以通过一个方法抛出(每次执行),但是有可能在尝试资源时抛出多个exception(可能抛出一个exception另一个可能会从资源尝试finally提供的隐含中抛出)。 编译器必须确定哪些“真正”抛出。 它select抛出显式代码(try块中的代码)引发的exception,而不是隐式代码(finally块)引发的exception。 因此,隐式块中抛出的exception被抑制(忽略)。 唯一发生在多个例外的情况下。

在Java7之前; 在代码中抛出exception,但被忽略。

例如)

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

采用这种新的方法,我们也可以处理这些被抑制的exception。

 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()中的exception默认情况下会作为抑制exception与tryexception一起添加。

还要知道,这与链式exception不同(JDK 1.4引入了这种exception ,旨在使其能够轻松地跟踪exception之间的因果关系)。

被禁止的exception是当closuresAutoCloseable资源时,在try-with-resources语句( 在Java 7中引入)中发生的额外exception。 由于在closuresAutoCloseable资源时可能会出现多个exception,因此将其他exception作为抑制exception附加到主exception 。

查看一段“试用资源”示例代码的字节码,使用标准JVMexception处理程序来适应资源尝试语义。

诠释下面的代码:

 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 

我认为这与“链式exception设施”有关。 随着堆栈跟踪的发展,这将影响该设备如何处理exception。 随着时间的推移,可以抑制作为一组链接exception的一部分的exception。 查看Throwable文档以获取更多详细信息。

你可以抑制Java 6中的exception(包括一些小技巧),

我创build了一个透明地处理Java 1.6和Java 1.7中的exception的实用程序。 你可以在这里find实现

所有你需要的是打电话给:

 public static <T extends Throwable> T suppress(final T t, final Throwable suppressed) 

抑制一个例外,并且

 public static Throwable [] getSuppressed(final Throwable t) { 

获取exception的抑制exception,以防有人仍然使用Java 1.6

ARM – 自动资源pipe理(从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()函数抛出exception,然后甚至close()函数[在finally块]抛出exception,然后给予更高的优先级,并返回到调用函数。 在这种情况下, Exception thrown by the readLine() method is ignored/suppressedException thrown by the readLine() method is ignored/suppressed 。 你可以在你的exception中链接exception,并从finally块重新抛出你的exception。

由于提供了java 7function来检索抑制的exception。 您可以在public final java.lang.Throwable[] getSuppressed()的可抛出对象上调用public final java.lang.Throwable[] getSuppressed()函数来查看抑制的exception。

例如。

 static String readFirstLineFromFileWithFinallyBlock(String path) throws Exception { try (BufferedReader br = new BufferedReader(new FileReader(path));) { return br.readLine(); } } 

现在如果br.readLine(); 行引发Exception1 ,然后让closures资源时抛出Exception2 [想象这发生在try-with-resource语句创build的隐式finally块中],那么Exception1将抑制Exception2。

这里有几点需要注意 –

  1. 如果尝试资源块抛出exception,即资源实例化,然后尝试块将不会执行和相同的exception将被抛出。
  2. 如果资源的实例成功,则尝试块在closures资源时抛出exception并引发exception,然后在closures资源时引发的exception被try块抛出的exception所抑制。
  3. 如果你提供显式的finally块,并且从该块中抛出exception,它将会抑制所有其他的exception。 (这个显式finally块在资源closures后执行)

我已经编译了大部分可能的场景,代码片段和后面的输出。

在java中抑制exception7

希望有所帮助。