这个包含 close() 调用的 finally 子句的原因是什么?

我正在学习在线java课程,使用Java编程入门

在 I/O 一章中,以下代码通过以下语句进行了介绍:

顺便说一句,在本程序结束时,您将在 try 语句中找到我们第一个有用的 finally 子句示例。当计算机执行 try 语句时,无论如何都可以保证执行其 finally 子句中的命令。

该程序位于11.2.1节的末尾,是一个简单的程序,只是从文件中读取一些数字并以相反的顺序写入它们。

main 方法中的相关代码是(数据是读取器,结果是写入器):

try {
    // Read numbers from the input file, adding them to the ArrayList.        
    while ( data.eof() == false ) {  // Read until end-of-file.
        double inputNumber = data.getlnDouble();
        numbers.add( inputNumber );
    }

    // Output the numbers in reverse order.        
    for (int i = numbers.size()-1; i >= 0; i--)
        result.println(numbers.get(i));

    System.out.println("Done!");        
} catch (IOException e) {
    // Some problem reading the data from the input file.
    System.out.println("Input Error: " + e.getMessage());
} finally {
    // Finish by closing the files, whatever else may have happened.
    data.close();
    result.close();
}

因此,我想知道为什么在这种情况下,当 try 或 catch 子句没有其他退出点时,finally 子句是有用的。难道关闭方法不能只是在main的主体中吗?

我想也许是因为理论上可能存在其他一些运行时异常,可以使程序崩溃,然后使Reader & Writers保持关闭状态,但是程序崩溃的事实不会关闭它们吗?


答案 1

你的想法是正确的:即使发生意外异常,最终块也将关闭资源。

您也是对的,如果这样的异常使整个应用程序崩溃,这是无关紧要的,但是通过查看此代码,您无法确定是否属于这种情况。可能还有其他异常处理程序来捕获该异常,因此将关闭逻辑放在 finally 块中是良好且正确的做法。

请注意,可能仍然存在一个错误隐藏:如果引发异常,将永远不会被调用。data.close()result.close()

根据您的环境,有关于如何修复该错误的各种类型。

  • 在java 7 ff中,您可以使用try-with-resources

  • 如果您使用的是Spring,可能会有一个类似于JdbcTemplate的适当模板

  • 如果这些都不适用,是的,你必须做一个尝试/最后在里面最后。退出丑陋。您绝对应该至少将其提取到注释中建议的方法中。

  • 概念上更干净,但在java pre 8中更冗长,是为了实现贷款模式。如果你没有碰巧与scala/clojure/haskell开发人员合作,它可能会比其他任何事情更令人困惑。


答案 2

这是出于一个非常简单的原因:这是最安全的方法,在Java 7和试用资源之前,即使捕获了异常,也可以保证您的资源被关闭。

想想如果你这样做了,会发生什么:

try {
    // some code, then

    resource.close();
} catch (SomeException e) {
    // etc
}

如果在资源关闭之前抛出 ,则可以泄漏资源。另一方面,将 放入 ,可以保证无论发生其他情况如何,它都会被关闭。SomeExceptionresource.close()finally

在Java 7中,您将使用以下命令:

try (
    final InputStream in = Files.newInputStream(Paths.get("somefile"));
    // Others
) {
    // work with "in" and others
} catch (Whatever e) {
}

然后,您的资源将在 之前关闭catch


顺便说一句,使用Java 6,关闭资源的最安全方法是使用Guava的Close


推荐