什么是禁止显示的异常?

What is a suppressed exception?

提问人:Raedwald 提问时间:10/21/2011 最后编辑:CommunityRaedwald 更新时间:1/20/2022 访问量:70803

问:

回答有关尾部调用优化的问题时,用户 soc 的评论提到 Java 7 有一个称为“抑制异常”的新功能,因为“添加了 ARM”(支持 ARM CPU?

在这种情况下,什么是“禁止显示的异常”?在其他情况下,“抑制的异常”将是捕获然后忽略的异常(很少是一个好主意);这显然是不同的东西。

Java 异常 try-with-resources

评论

0赞 Raedwald 10/21/2011
我在“Java 编程语言增强功能”描述中没有看到它 download.oracle.com/javase/7/docs/technotes/guides/language/......
21赞 daniel kullmann 10/21/2011
ARM 表示自动资源管理,例如 infoq.com/news/2010/08/arm-blocks
7赞 Brad Cupit 4/19/2017
在此上下文中,ARM 是 try-with-resources 的旧名称。他们停止使用 ARM,并在 Java 7 发布前的某个时候开始使用 try-with-resources。@danielkullmann 在 ARM 所代表的方面是正确的

答:

58赞 Jon Skeet 10/21/2011 #1

我相信评论者所指的是一个异常,当它被抛出在try-with-resources块的隐式块中时,在从该块抛出现有异常的上下文中时,该异常被半忽略:finallytry

可以从与 try-with-resources 语句关联的代码块引发异常。在示例 writeToFileZipFileContents 中,可以从 try 块引发异常,并且当 try-with-resources 语句尝试关闭 ZipFile 和 BufferedWriter 对象时,最多可以从该语句引发两个异常。如果从 try 块引发异常,并且从 try-with-resources 语句引发一个或多个异常,则禁止从 try-with-resources 语句引发的这些异常,并且该块引发的异常是 writeToFileZipFileContents 方法引发的异常。可以通过从 try 块引发的异常中调用 Throwable.getSuppressed 方法来检索这些抑制的异常。

(这是引用链接页面中名为“抑制的异常”的部分。

评论

2赞 Raedwald 10/21/2011
相关API调用:download.oracle.com/javase/7/docs/api/java/lang/...
0赞 Jon Skeet 10/21/2011
@Raedwald:大多数情况下,是的,我想是的。
6赞 JBert 11/22/2011
@JonSkeet @Raedwald :我相信这个答案没有考虑到在 Java 7 之前就存在被抑制的异常(我不是在谈论被忽略的异常):如果一个块在块也抛出异常时抛出异常,则该块的原始异常将丢失或“抑制”(参见 http://accu.org/index.php/journals/236了解更多信息)。Java 7 刚刚添加了一种方便的方法来存储块中的异常,因为 try-with-resources 隐式生成。finallytrytryfinallyfinally
5赞 Aniket Thakur 12/26/2014
但需要注意的一点是,如果我们在 try-with-resource 语句中显式提供 finally 块,并且从中抛出异常,那么它优先于 try 或 try-with-resource 块中抛出的异常。
81赞 John B 10/21/2011 #2

为了澄清 Jon 回答中的引述,一个方法(每次执行)只能抛出一个异常,但在 的情况下,可能会抛出多个异常。例如,一个可能被抛出到块中,另一个可能被抛出。try-with-resourcesfinallytry-with-resources

编译器必须确定要“真正”抛出其中的哪一个。它选择抛出显式代码(块中的代码)中引发的异常,而不是隐式代码(块)引发的异常。因此,隐式块中抛出的异常将被禁止(忽略)。这仅在出现多个异常的情况下发生。tryfinally

评论

1赞 Raedwald 10/21/2011
因此,抑制异常是新功能的结果,这意味着我们不再需要编写繁琐的...打开和 ING 文件时的子句: stackoverflow.com/questions/3305405/...tryfinallyclose()
4赞 John B 11/20/2014
@KanagaveluSugumar 构造函数用于将导致异常的异常包装在另一个可能更具描述性的异常中。然而,在这种情况下,我们谈论的是两个没有因果关系的不同例外。异常 A 不会导致异常 B,因此将一个包装在另一个中是没有意义的。此外,您假设编码人员显式抛出第二个异常,并且有权访问第一个异常。如果两者都由库调用抛出,则情况并非如此。Exception(Exception cause)
2赞 Kanagavelu Sugumar 12/3/2014
@JohnB我认为你的说法是错误的。“编译器必须确定”真正“抛出其中的哪一个。它选择抛出显式代码(try 块中的代码)中引发的异常“ 但编译器只会选择 finally 异常,并且 try 异常将被抑制。
1赞 John B 12/3/2014
@KanagaveluSugumar 每个文档:If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed
1赞 Puce 7/1/2019
请注意,禁止的异常不仅对 try-with-resources 有用,而且对自定义代码也很有用,通常在 catch- 或 finally-clause 中,否则另一个异常会隐藏原始异常。
9赞 Go Dan 10/21/2011 #3

禁止的异常是关闭 AutoCloseable 资源时,try-with-resources 语句(在 Java 7 中引入)中发生的其他异常。由于在关闭资源时可能会发生多个异常,因此其他异常将作为禁止的异常附加到主异常。AutoCloseable

查看一段 try-with-resources 示例代码的字节码,使用标准 JVM 异常处理程序来适应 try-with-resources 语义。

-1赞 Jean-Simon LaRochelle 3/26/2013 #4

我认为这与“链式异常设施”有关。随着堆栈跟踪的发展,它将影响此工具处理异常的方式。随着时间推移,属于一组链式异常的异常可能会被抑制。有关更多详细信息,请查看 Throwable 文档

0赞 Aniket Thakur 10/17/2013 #5

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

现在,如果函数抛出异常,然后甚至函数 [in finally block] 抛出异常,那么后者被赋予更多优先级并被抛回调用函数。在本例中,.您可以在异常中链接导致异常,并从 finally 块重新抛出异常。readLine()close()Exception thrown by the readLine() method is ignored/suppressed

由于提供了检索抑制异常的功能。您可以对捕获的可抛出对象调用函数来查看抑制的异常。java 7public final java.lang.Throwable[] getSuppressed()

例如。

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

现在,如果抛出行,然后假设在关闭资源时抛出 [想象一下这发生在 try-with-resource 语句创建的隐式 finally 块中],则 Exception1 会抑制 Exception2。br.readLine();Exception1Exception2

这里需要注意的几点——

  1. 如果 try-with-resource 块抛出异常,即在资源实例化时,则 try 块将不会执行,并且会抛出相同的异常。
  2. 如果资源实例化成功,则 try 块会引发异常,并且在关闭资源时会引发异常,然后关闭资源时引发的异常会被 try 块抛出的异常抑制。
  3. 如果提供显式 finally 块,并且从该块抛出异常,它将禁止所有其他异常。(此显式 finally 块在资源关闭后执行)

在下面的帖子中,我已经用代码片段和输出编译了大多数可能的场景。

Java 7 中禁止的异常

希望能有所帮助。

评论

1赞 Martin Andersson 11/5/2013
但是,在这种情况下,源自 try{} 块的 that 不会被自动抑制。程序员可以选择这样做,而你没有。只有在需要时才尝试使用资源时,才会自动禁止显示异常。当他这样做时,你的等价 finally 块中的例外将被压制。Exception
1赞 Aniket Thakur 12/27/2014
@MartinAndersson 你是对的。当我写下答案时,我有些困惑。我希望编辑后的答案能提供更好的见解。
0赞 user2179737 6/11/2014 #6

您也可以在 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) {

获取 Exception 的抑制异常,以防有人仍在使用 Java 1.6

27赞 Kanagavelu Sugumar 11/20/2014 #7

在 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 中,try-with-resources;AutoCloseable::close() 异常 默认情况下,与 try 异常一起添加为抑制异常。

还要注意,这与链式异常不同(在 JDK 1.4 中引入,旨在使轻松跟踪异常之间的因果关系成为可能。

14赞 Adil 5/13/2016 #8

承认以下代码:

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!

删除块后,您将获得:finallyjava.lang.RuntimeException: from catch!

删除块后,您将获得:catch

Exception in thread "main" java.lang.RuntimeException: from try!
    Suppressed: java.lang.RuntimeException: from IOManip.close