【问题标题】:Am I using the Java 7 try-with-resources correctly我是否正确使用 Java 7 try-with-resources
【发布时间】:2013-07-13 02:59:15
【问题描述】:

如果抛出异常,我希望缓冲读取器和文件读取器关闭并释放资源。

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
    {
        return read(br);
    } 
}

但是,是否需要有 catch 子句才能成功关闭?

编辑:

基本上,Java 7 中的上述代码是否等同于 Java 6 中的以下代码:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{

    BufferedReader br = null;

    try
    {
        br = new BufferedReader(new FileReader(filePath));

        return read(br);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        try
        {
            if (br != null) br.close();
        }
        catch(Exception ex)
        {
        }
    }

    return null;
}

【问题讨论】:

  • 再次阅读您的问题后,我不确定我是否理解它。你能解释一下吗?
  • 嗨。 Cheetah,我正在尝试了解 Java 6 示例中第一个 catch 的作用。即catch (Exception ex) { throw ex; } — 它只是重新抛出异常,它什么都不做,它可以很容易地删除而不会造成任何伤害。还是我错过了什么?

标签: java-7 try-with-resources


【解决方案1】:

正确,不需要catch 子句。 Oracle java 7 文档说资源将被关闭无论是否实际抛出异常。

只有当你想对异常做出反应时,你才应该使用catch 子句。 catch 子句将在资源关闭后执行

这是来自Oracle's tutorial的sn-p:

以下示例从文件中读取第一行。它使用一个 BufferedReader 实例从文件中读取数据。缓冲阅读器 是程序完成后必须关闭的资源 它:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
} // In this example, the resource declared in the try-with-resources statement is a BufferedReader.

... 因为 BufferedReader 实例是在 try-with-resource 语句,不管是否 try 语句正常或突然完成(由于 方法 BufferedReader.readLine 抛出 IOException)。

编辑

关于新编辑的问题:

Java 6 中的代码执行catch,然后执行finally 块。这会导致资源仍可能在 catch 块中打开。

在 Java 7 语法中,资源在catch 块之前关闭,因此在catch 块执行期间资源已经关闭。这记录在上面的链接中:

在 try-with-resources 语句中,运行任何 catch 或 finally 块 在声明的资源关闭之后。

【讨论】:

    【解决方案2】:

    在这种特殊情况下,您对 try-with-resources 的使用可以正常工作,但总的来说它并不完全正确。您不应该像这样链接资源,因为它可能会导致令人不快的意外。假设你有一个可变的缓冲区大小:

    public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
    {
        int sz = /* get buffer size somehow */
        try (BufferedReader br = new BufferedReader(new FileReader(filePath), sz))
        {
            return read(br);
        } 
    }
    

    假设出了点问题,而您最终得到的 sz 是否定的。在这种情况下,您的文件资源(通过 new FileReader(filePath) 创建)将不会关闭。

    为了避免这个问题,你应该像这样单独指定每个资源:

    public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
    {
        int sz = /* get buffer size somehow */
        try (FileReader file = new FileReader(filePath);
             BufferedReader br = new BufferedReader(file, sz))
        {
            return read(br);
        } 
    }
    

    在这种情况下,即使 br 的初始化失败 file 仍然会关闭。您可以在herehere 找到更多详细信息。

    【讨论】:

    • 我试图理解为什么在 sz 为负数时抛出 IllegalArgumentException 时通过 new FileReader(filePath)) 创建的资源不会关闭。无论抛出任何异常,try-with-resources 是否都会关闭所有 AutoClosable 资源?
    • @PrasoonJoshi 不,它只为在 try-with-resources 初始化程序中声明的变量调用 .close()。这就是为什么在这个例子中把它分成两个声明就行了。
    • Andrii 和@Mario 你是对的,也是错的。在第一个示例中,FileReader 没有被 try-with-resource 逻辑关闭。但是当 BufferedReader 关闭时,它也会关闭包装的 FileReader。为了证明,请查看 java.io.BufferedReader.close() 的源代码。因此,应该首选第一个示例中的代码,因为它更简洁。
    • @jschreiner 没错,虽然 Andrii 的(有些人为的)问题,其中sz < 0 导致构造函数抛出异常,实际上会导致资源泄漏。
    • @mario 我同意。外部构造函数可能会失败,内部资源会泄漏。以前没看过,谢谢。
    猜你喜欢
    • 2021-08-03
    • 2013-06-30
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多