什么是被抑制的异常?

Rae*_*ald 66 java exception-handling exception try-with-resources

注释(用户SOC上的)回答关于尾调用优化的问题提到了Java 7中有一个称呼,是因为"加ARM的"的"抑制异常",新的功能(适用于ARM CPU的支持?).

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

Joh*_*n B 57

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

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

  • @KanagaveluSugumar`Exception(异常原因)`构造函数用于将另一个可能更具描述性的异常包装起来.然而,在这种情况下,我们谈论的是两个不存在因果关系的明显例外.异常A没有导致异常B因此将一个包装在另一个中是没有意义的.此外,您假设编码器明确抛出第二个异常并且可以访问第一个异常.如果由库调用引发的两者都不是这种情况. (3认同)
  • @JohnB 我认为你的说法是错误的。“编译器必须确定“真正”抛出其中的哪一个。它选择抛出显式代码中引发的异常(try 块中的代码)”但编译器将仅选择finally 异常,并且try 异常将被抑制。 (2认同)

Jon*_*eet 50

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

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

(这是从链接页面引用一个名为"禁止例外"的部分.)

  • @JonSkeet @Raedwald:我相信这个答案没有考虑到在Java 7之前存在被抑制的异常(我不是在讨论_ignored_异常):如果```块也引发异常,当`try`块也抛出异常时,来自`try`块的原始异常丢失或"被抑制"(参见[http://accu.org/index.php/journals/236 ](http://accu.org/index.php/journals/ 236)了解更多信息).Java 7刚刚添加了一个方便的方法来存储`finally`块中的异常,因为`finally`是由try-with-resources隐式生成的. (6认同)
  • 但需要注意的一点是,如果我们在try-with-resource语句中显式提供finally块并且从中抛出异常,那么它优先于try或try-with-resource块抛出的异常. (5认同)
  • 相关API调用:http://download.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getSuppressed%28%29 (2认同)

Kan*_*mar 17

在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 {
}
Run Code Online (Sandbox Code Playgroud)

JDK 7中的Throwable类添加了一个新的构造函数和两个新方法.如下所示:

Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);
Run Code Online (Sandbox Code Playgroud)

使用这种新方法,我们也可以处理这些被抑制的异常.

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 {
}
Run Code Online (Sandbox Code Playgroud)

在Java7中尝试资源; AutoCloseable :: close()的异常默认添加为抑制异常以及try异常.

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


Dan*_*ruz 9

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

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


Adi*_*dil 7

隐藏下面的代码:

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!");
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

通过所有线路,您将得到: 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
Run Code Online (Sandbox Code Playgroud)