31

我读到catchtry-with-resources 中的块是可选的。我尝试Connection在 try-with-resources 块中创建一个对象,没有后续catch块,只是从 eclipse 中获取编译器错误:“自动调用SQLException引发的未处理异常类型。”close()

由于可以在 try-with-resources 中使用的每个资源都实现AutoCloseable,因此在调用该方法时可能会引发异常,因此close()我不明白该catch子句如何是可选的,因为它不允许我跳过从close().

是不是有什么特殊要求,具体实现AutoCloseable不直接声明其close()方法中抛出的异常?(例如,使用不抛出任何异常 AutoCloseable的覆盖)?close() throws Exceptionclose()

..或者这可能只是一个日食问题?

编辑:这是仍然触发问题的最简单的代码片段:

try (Connection con = dataSource.getConnection()) {
  /*...*/

}

关于这是否与使用 JNDI 数据源有关的想法?

提前致谢。

4

5 回答 5

26

close()如果不能抛出已检查的异常,则它是可选的。但是,如果close()可以,则需要以正常方式处理已检查的异常,或者使用catch块,或者从该块所在的方法中抛出try-with-resources

更多细节在JLS 14.2.3

14.20.3.2。扩展资源尝试

带有至少一个 catch 子句和/或 finally 子句的 try-with-resources 语句称为扩展的 try-with-resources 语句。

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

try ResourceSpecification
    Block
[Catches]
[Finally]

由以下对嵌套在 try-catch 或 try-finally 或 try-catch-finally 语句中的基本 try-with-resources 语句的翻译给出:

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

翻译的效果是将资源规范“放入”try 语句中。这允许扩展的 try-with-resources 语句的 catch 子句捕获由于任何资源的自动初始化或关闭而导致的异常。

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

关于这是否与使用 JNDI 数据源有关的想法?

是的。

在您提供的示例try-with-resources块中,有必要捕获异常并处理,或者从块所在的方法中抛出,因为SQLException是一个已检查的异常。

于 2014-08-26T02:26:22.700 回答
3

您可能只是抛出异常(或在另一个 try-catch 块中捕获它):

private static void test() throws IOException {
    try(InputStream is = new FileInputStream("test.txt")) {
        while(is.read() > -1) {
        }
    } finally {
        // Will get executed, even if exception occurs
        System.out.println("Finished");
    }
}
于 2014-08-26T02:27:16.227 回答
0

您可以通过声明 AutoClosable 的 close() 方法而无需任何异常或带有 RuntimeException 来创建不需要显式捕获块的 AutoClosable。没有任何异常,很明显不需要 catch-block。此外,编译器不会静态检查要捕获的 RuntimeException(与检查的异常相反)。

例子:

public class AutoClosableDemo
{

    public static void main( final String[] args )
    {
        try (MyAutoCloseable1 mac1 = new MyAutoCloseable1())
        {
            System.out.println( "try-with-resource MyAutoCloseable1" );
        }
        try (MyAutoCloseable2 mac2 = new MyAutoCloseable2())
        {
            System.out.println( "try-with-resource MyAutoCloseable2" );
        }
        // The following is not allowed, because
        // "Unhandled exception type Exception thrown by automatic close() invocation on mac3"
        // try (MyAutoCloseable3 mac3 = new MyAutoCloseable3())
        // {
        // System.out.println( "try-with-resource MyAutoCloseable13" );
        // }
        System.out.println( "done" );
    }

    public static class MyAutoCloseable1 implements AutoCloseable
    {
        @Override
        public void close()
        {
            System.out.println( "MyAutoCloseable1.close()" );
        }
    }

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

    public static class MyAutoCloseable3 implements AutoCloseable
    {
        @Override
        public void close() throws Exception
        {
            System.out.println( "MyAutoCloseable3.close()" );
        }
    }
}
于 2019-07-05T10:59:37.553 回答
0

您可以检查 JLS,但实际上有一个相对简单的推理,为什么这是该语言应该表现的唯一正确方式。

检查异常的主要规则是必须处理方法声明的任何检查异常,方法是捕获它或让调用方法抛出它。

try-with-resources 总是(隐式地)调用 close 方法。

因此,如果您使用的 AutoClosable 的特定 close 方法(由try中声明的类型确定)声明抛出检查异常,例如 SQLException,则您确实需要在某处处理此检查异常,否则可能违反规则!

如果 close 方法没有声明它抛出一个受检异常,则不违反规则,您不需要处理受检异常来隐式调用 close 方法。如果您确实尝试捕获从未声明为抛出的已检查异常,则实际上是编译失败。

于 2016-04-15T12:27:03.447 回答
-1

并非每个 Java 类 (!) 都会引发异常。有时您只想使用 try-with-resources 来使用自动关闭功能,仅此而已。

BufferedReader br = new BufferedReader(new FileReader(path));
try {
    return br.readLine();
} finally {
    if (br != null) br.close();
}

这个 catch 是可选的,因为 readLine() 不会抛出(检查的)异常。

是的,close() 可能会抛出异常,但 try-with-resources 也可以处理该异常。

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
} 

所以这个 try-with-resources 不需要捕获。

于 2014-08-26T02:25:02.180 回答