我试图了解Java SE7中的抑制异常,我在下面发布了2个示例,它们是相似的,在下面的示例中,我的印象是当新的"主要异常"发生了,被抑制的被忽略了,例如我期望输出是" java.lang.RuntimeException:y",但答案是:
java.lang.RuntimeException: y
suppressed java.lang.RuntimeException: a
以下是代码:
class Animal implements AutoCloseable{
@Override
public void close() {
throw new RuntimeException("a");
}
}
public class ExceptionsDemo {
public static void main(String[] args) throws IOException {
try(Animal a1 = new Animal();){
foo();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
}
static void foo() {
try {
throw new RuntimeException("x");
} catch (Exception e) {
throw new RuntimeException("y");
}
}
}
我的理解是在tryWithResources子句之后," a"是主要的Exc,然后在foo()中,x变为主要的exc而a被压制,但是在catch中,我认为y将成为独奏主要的exc并且将忽略所有其他例外,包括被压制的那些?
像第二个例子一样,它执行我刚才提到的,它输出java.lang.RuntimeException:c,没有被抑制的异常。
public class ExceptionDemo2 {
class Animal implements AutoCloseable{
@Override
public void close() {
throw new RuntimeException("a");
}
}
public static void main(String[] args) {
try{
new ExceptionDemo2().go();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
}
void go(){
try(Animal a = new Animal()){
throw new IOException();
}catch(Exception e){
throw new RuntimeException("c");
}
}
}
输出:java.lang.RuntimeException: c
答案 0 :(得分:4)
你的例子
try(Animal a1 = new Animal();){
foo();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
终止,因为foo()
会引发RuntimeException
(y
)。这是catch
的目标。由于执行离开try
块,因此所有声明资源都将关闭。关闭Animal
实例时,会抛出另一个RuntimeException
(a
)。那个被压制,因为它不是根本原因。
JLS here解释了try-with-resources
到try-catch-finally
块的转换。
基本的try-with-resources语句的含义:
try ({VariableModifier} R Identifier = Expression ...) Block
通过以下转换给出局部变量声明 和一个try-catch-finally语句:
{ final {VariableModifierNoFinal} R Identifier = Expression; Throwable #primaryExc = null; try ResourceSpecification_tail Block catch (Throwable #t) { #primaryExc = #t; throw #t; } finally { if (Identifier != null) { if (#primaryExc != null) { try { Identifier.close(); } catch (Throwable #suppressedExc) { #primaryExc.addSuppressed(#suppressedExc); } } else { Identifier.close(); } } } }
,其中
如果资源规范声明了一个资源,那么
ResourceSpecification_tail
为空(并且try-catch-finally 声明本身不是资源试用声明。)
上面的代码基本上翻译为
try {
final Animal a1 = new Animal();
Throwable thr = null;
try {
foo();
} catch (Throwable root) {
thr = root;
throw root;
} finally {
if (a1 != null) {
if (thr != null) {
try {
a1.close();
} catch (Throwable suppressed) {
thr.addSuppressed(suppressed); // <<<<<< suppressing the failure of 'close'
}
} else {
a1.close();
}
}
}
} catch (Exception e) {
System.err.println(e);
for (Throwable t : e.getSuppressed()) {
System.err.println("suppressed " + t);
}
}
答案 1 :(得分:2)
这是令人困惑的,因为它将try-with-resources与资源试图解决的异常屏蔽行为混合在一起。
此外,您似乎还没有意识到要禁止异常的含义。抑制意味着异常被添加到现有异常,而不是被抛出,并且在进程中导致try-block中抛出的异常丢失(通常的术语被“屏蔽”)。
异常屏蔽意味着从finally或catch块抛出的异常导致try块中抛出的任何异常被丢弃。由于try-blocks中抛出的异常通常描述了你的错误,并且关闭时抛出的异常通常是无趣的,这是一件坏事;创建了try-with-resources以尝试减少此问题的普遍性。
所以在你的第一个例子中,foo在try块内的a1上被调用,在foo中,catch中抛出的异常,y,掩盖了foo的try块中抛出的异常。然后,当退出try-with-resources块时,将调用close方法,并将close上抛出的异常添加到正在进行的y异常中。所以你的printlns显示y,然后遍历附加到y的抑制异常。
在第二个例子中,c是go方法抛出的内容(它与上面描述的屏蔽行为相同)。抛出go方法try块中的IOException,在出路时调用close方法,导致close上的异常被添加到IOException作为被抑制的异常,然后IOException被c掩盖。因为被屏蔽,并且被抑制的异常附加到a,我们也失去了被抑制的异常。关闭时抛出的c异常没有与之关联的抑制异常,因为它是在退出try-with-resources块之后生成的。
答案 2 :(得分:0)
来自Oracle文档http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html:
如果从try块抛出异常并且try-with-resources语句抛出了一个或多个异常,那么将禁止从try-with-resources语句抛出的异常。您可以通过从try块抛出的异常中调用Throwable.getSuppressed方法来检索这些抑制的异常。
正如所料,第一个例子给出了输出:
java.lang.RuntimeException: y
suppressed java.lang.RuntimeException: a
在第二个代码段中也有一个异常抑制的情况。要验证我已将您的功能修改为:
void go() {
try (Animal a = new Animal()) {
throw new IOException();
} catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
System.err.println("suppressed " + t);
}
throw new RuntimeException("c");
}
}
然后输出将是:
suppressed java.lang.RuntimeException: a
java.lang.RuntimeException: c