我试图理解Java SE7中被抑制的Exceptions,我发了2个下面的例子,它们是相似的,在下面的例子中,我的印象是当新的 "main Exception "发生时,被抑制的Exception会被忽略,例如我希望输出是 "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 "是main Exc,然后在foo()中,x成为main exc,而a被抑制,但在catch中,我想y会成为单独的main 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,没有被抑制的异常。java.lang.RuntimeException: c
你的例子
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
)被抛出。这个被压制了,因为它不是根本原因。
的翻译是 try-with-resources
到 try-catch-finally
块的解释在JLS中。此处.
一个基本的 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-with-resources 语句)。
你上面的代码基本上翻译成这样
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);
}
}
这很令人困惑,因为它把 try-with-resources 和异常屏蔽行为混在一起了,而 try-with-resources 本来就是要解决这个问题的。
此外,你似乎不知道异常被抑制的含义。抑制的意思是,异常被附加在一个已有的异常上,而不是被抛出,在进展中导致try-block内抛出的异常丢失(通常的说法是 "屏蔽")。
异常掩盖意味着从final或catch块中抛出的异常会导致任何从try块中抛出的异常被丢弃。由于在 try 块中抛出的异常通常是描述你的错误的,而在关闭时抛出的异常通常是无趣的,这是件坏事;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被掩盖了,而被压制的异常是附加在a上的,所以我们也失去了被压制的异常。关闭时抛出的c异常没有与之相关的压制异常,因为它是在退出try-with-resources块之后产生的。
从Oracle文档中可以看到 http:/docs.oracle.comjavasetutorialessentialexceptionstryResourceClose.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