为什么在 Java 中的 try-with-resources 构造中,资源的 close() 方法在 catch 之前被调用?

2022-09-03 07:29:04

我碰巧意识到,情况就是这样。请参阅下面的示例:

public class AutoClosableTest {
    public static void main(String[] args) throws Exception {
        try (MyClosable instance = new MyClosable()) {
            if (true) {
                System.out.println( "try" );
                throw new Exception("Foo");
            }
        } catch( Exception e ) {
            System.out.println( "Catched" );
        } finally {
            System.out.println( "Finally" );
        }
    }

    public static class MyClosable implements AutoCloseable {
        @Override
        public void close() throws Exception {
            System.out.println( "Closed." );
        }
    }
}

它打印:

尝试
关闭。
终于被
抓住了

问题

使用资源进行试用旨在避免带有空检查的混乱的最终部分,并避免泄漏资源。为什么在捕获部分之前关闭资源?它背后的原因/想法/局限性是什么?


答案 1

答案可以在JLS §14.20.3.2中找到;关键部分是最后两段,特别是倒数第二段的最后一句(我已经强调了这一点):

至少包含一个子句和/或子句的语句称为扩展语句。try-with-resourcescatchfinallytry-with-resources

扩展语句的含义:try-with-resources

try ResourceSpecification
    Block
[Catches]
[Finally]

通过对嵌套在 or 语句中的基本语句的以下转换给出:try-with-resourcestry-catchtry-finallytry-catch-finally

try {
    try ResourceSpecification
        Block
}
[Catches]
[Finally]

转换的效果是将资源规范放在语句的“内部”。这允许扩展的资源试用语句的 catch 子句捕获由于任何资源的自动初始化或关闭而导致的异常。try

此外,在执行块时,所有资源都将被关闭(或试图关闭),这与关键字的意图一致。finallyfinally


答案 2

推荐