什么是被抑制的异常?

时间:2011-10-21 12:31:12

标签: java exception exception-handling try-with-resources

socanswer的评论(由用户a question about tail call optimisation)提到Java 7有一个名为“抑制异常”的新功能,因为“添加了ARM”(支持ARM CPU?)。

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

8 个答案:

答案 0 :(得分:55)

为了澄清Jon的答案中的引用,一个方法只能抛出一个异常(每次执行),但在try-with-resources的情况下,有可能抛出多个异常。例如,可能会在块中抛出一个,而另一个可能会从finally提供的隐式try-with-resources抛出。

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

答案 1 :(得分:48)

我认为评论者指的是一个异常,当它被抛出try-with-resources块的隐式finally块内时,在从现有异常抛出的上下文中被忽略。 try阻止:

  

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

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

答案 2 :(得分:13)

在Java7之前;代码中抛出异常,但在某种程度上被忽略了。

e.g。)

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()中的异常   默认情况下会添加为抑制异常以及尝试异常。

同时意识到这与chained exceptions不同(在JDK 1.4中引入,旨在使得可以轻松跟踪异常之间的因果关系。)

答案 3 :(得分:9)

Suppressed exceptions是在introduced in Java 7资源关闭时在try-with-resources语句(AutoCloseable)内发生的其他异常。由于在关闭AutoCloseable资源时可能会出现多个例外情况,因此primary exception as suppressed exceptions会附加其他例外情况。

查看一段try-with-resources示例代码的字节码,标准JVM exception handlers用于容纳try-with-resources语义。

答案 4 :(得分:6)

隐藏下面的代码:

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

答案 5 :(得分:0)

我认为这与“链式异常工具”有关。随着堆栈跟踪的发展,它将影响此工具处理异常的方式。随着时间的推移,可以抑制属于一组链式异常的异常。请查看the Throwable documentation了解更多详情。

答案 6 :(得分: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()函数[在finally块中]抛出异常,则后者被赋予更多优先级并被抛回到调用函数。在这种情况下Exception thrown by the readLine() method is ignored/suppressed。您可以在异常中链接导致异常,并从finally块重新抛出异常。

由于提供了java 7功能来检索已抑制的异常。您可以在catched throwable对象上调用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 try将不会执行,并且将抛出相同的异常。
  2. 如果资源的实例化成功,try块抛出异常并在关闭资源时抛出异常,则关闭资源时抛出的异常会被try块抛出的异常所抑制。
  3. 如果你提供显式finally块并且从该块抛出异常,它将禁止所有其他异常。 (这个显式的finally块在资源关闭后执行)
  4. 我已经使用以下帖子编写了代码片段和输出的大部分可能方案。

    Suppressed exceptions in java 7

    希望有所帮助。

答案 7 :(得分:0)

您也可以在Java 6中抑制异常(涉及一些小技巧),

我创建了一个透明地处理Java 1.6和Java 1.7中的异常处理的实用程序。您可以找到实施here

您只需致电:

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

压制异常,

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

获取异常的抑制异常,以防任何人仍然使用Java 1.6