84

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

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

4

8 回答 8

70

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

编译器必须确定“真正”抛出哪些。它选择抛出在显式代码(块中的代码)中引发的try异常,而不是由隐式代码(finally块)抛出的异常。因此,隐式块中抛出的异常被抑制(忽略)。这只发生在多个异常的情况下。

于 2011-10-21T12:41:15.363 回答
55

我相信评论者所指的是一个异常,当它在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”的部分。)

于 2011-10-21T12:34:00.750 回答
26

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 引入的,旨在使轻松跟踪异常之间的因果关系成为可能。)

于 2014-11-20T06:42:56.420 回答
12

承认以下代码:

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
于 2016-05-13T09:42:06.510 回答
9

抑制的异常是资源关闭时在 try-with-resources 语句(Java 7 中引入)中发生的附加异常。AutoCloseable因为关闭AutoCloseable资源时可能会发生多个异常,所以附加异常作为抑制异常附加到主要异常

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

于 2011-10-21T13:27:50.567 回答
0

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。

这里有几点需要注意——

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

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

java 7中的抑制异常

希望有帮助。

于 2013-10-17T12:11:55.833 回答
0

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

于 2014-06-11T14:29:50.353 回答
-1

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

于 2013-03-25T21:54:03.547 回答