Java SE7 中的抑制异常

use*_*412 3 java exception-handling

我试图理解 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");
        }    
    }
}
Run Code Online (Sandbox Code Playgroud)

我的理解是,在 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");
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

输出: java.lang.RuntimeException: c

Sot*_*lis 5

你的榜样

try(Animal a1 = new Animal();){
    foo();
}
catch(Exception e){
    System.err.println(e);
    for(Throwable t : e.getSuppressed()){
        System.err.println("suppressed "+ t);
    }
}
Run Code Online (Sandbox Code Playgroud)

因为foo()抛出一个RuntimeException( y) 而终止。这就是catch. 因为执行离开try块,所有声明的资源都被关闭。关闭Animal实例时,会抛出另一个RuntimeException( a)。那个被压制了,因为它不是根本原因。

try-with-resourcestry-catch-finally块的翻译在 JLS 中解释,这里

基本 try-with-resources 语句的含义:

try ({VariableModifier} R Identifier = Expression ...)
    Block
Run Code Online (Sandbox Code Playgroud)

由以下转换为局部变量声明和 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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在哪里

如果资源规范声明了一个资源, 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);
    }
}
Run Code Online (Sandbox Code Playgroud)