为什么try-with-resources catch块选择性地可选?

时间:2014-08-26 02:18:20

标签: java try-with-resources autocloseable

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

由于可以在try-with-resources中使用的每个资源都实现AutoCloseable,因此在调用close()方法时可能会抛出异常,我不明白{{1因为它不允许我跳过从catch捕获异常,所以子句是可选的。

是否有一些特殊要求close()的具体实现不直接声明其AutoCloseable方法中抛出的任何异常? (例如,使用close()覆盖AutoCloseable的{​​{1}},但不会抛出任何异常)?

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

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

close() throws Exception

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

提前致谢。

5 个答案:

答案 0 :(得分:21)

如果close()无法抛出已检查的异常,则可选。但是,如果close()可以,则需要以正常方式处理已检查的异常,或者使用catch块,或者通过抛出try-with-resources块所在的方法来处理。 / p>

更多详情请见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-resourses 块中,有必要捕获异常并处理,或者从块所在的方法中抛出,因为SQLException是一个经过检查的例外

答案 1 :(得分:2)

你可能只是抛出异常(或在另一个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");
    }
}

答案 2 :(得分:0)

并非每个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();
} 

因此,这种资源尝试并不需要捕获。

答案 3 :(得分:0)

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

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

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

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

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

答案 4 :(得分:0)

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

示例:

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()" );
        }
    }
}