Java 为什么try-with-resources-catch块是可选的?

Java 为什么try-with-resources-catch块是可选的?,java,try-with-resources,autocloseable,Java,Try With Resources,Autocloseable,我读到try with resources中的catch块是可选的。 我尝试在try with resources块中创建一个连接对象,没有后续的捕获块,结果从eclipse获得编译器错误: “自动close()调用引发的未处理异常类型SQLException。” 由于可以在try with resources中使用的每个资源都实现了AutoCloseable,因此在调用close()方法时可能会引发异常,因此我不理解catch子句是如何可选的,因为它不允许我从close()跳过捕获异常 是否有

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

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

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

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

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

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

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

提前谢谢

不是每个Java类(!)都会抛出异常。有时,您只想尝试使用资源来使用自动关闭功能,而不想使用其他功能

BufferedReader br = new BufferedReader(new FileReader(path));
try {
    return br.readLine();
} finally {
    if (br != null) br.close();
}
此捕获是可选的,因为readLine()不会引发(选中的)异常

是的,close()可能引发异常,但try with resources也会处理该异常

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

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

如果
close()
无法引发选中的异常,则此选项是可选的。但是,如果
close()
可以,则需要以正常方式处理选中的异常,可以使用
catch
块,也可以从
try with resources
块所在的方法中抛出

更多细节见附件

14.20.3.2。扩展资源试用

至少有一个catch子句和/或finally子句的try with resources语句称为extended try with resources语句

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

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

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

此外,根据finally关键字的意图,在执行finally块时,所有资源都已关闭(或试图关闭)

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

是的


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

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


您可以检查JLS,但实际上有一个相对简单的理由,说明为什么这是该语言唯一正确的行为方式

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

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

因此,如果您使用的AutoClosable的特定close方法(由try中声明的类型决定)声明抛出一个选中的异常,例如SQLException,那么您确实需要在某个地方处理这个选中的异常,否则可能会违反规则


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

您可以创建不需要显式catch块的AutoClosable,方法是在没有任何异常或运行时异常的情况下声明AutoClosable的close()方法。毫无例外,显然不需要catch块。此外,编译器不会静态检查要捕获的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()" );
        }
    }
}

尝试在不使用Eclipse的情况下在命令行上编译您可以提供一个
AutoClosable
实现,该实现不会引发异常,在这种情况下,您不需要捕获任何内容,或者,您可以在方法签名中添加一个
throws
子句,在这种情况下,您不需要
catch
子句。感谢您的回答和包含方法Edwin上有关throws的注释。我忘记了这样做可以使try语句不必捕获异常。我不明白。本例不使用try with resources。我展示了try with resources替换的代码。它也没有catch,这就是为什么try-with-resources必须将catch设置为可选的原因。创建资源的位置(在本例中是缓冲区读取器)确实可能引发IOException。如果您尝试使用资源,您需要一个
捕获
。但这与OP的问题无关。捕获在这里仍然是可选的。您可以继续,但不证明它是可选的。显示使用此签名的整个函数签名。无论您是否使用try-with-resources,您都必须声明throws子句或执行catch。谢谢您提供的详细答案。我很惊讶
try {
    try ResourceSpecification
       Block
}
[Catches]
[Finally]
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");
    }
}
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()" );
        }
    }
}