我是否正确使用了Java 7的try-with-resources

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (18)

我希望缓冲的阅读器和文件阅读器关闭,并在抛出异常时释放资源。

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;
}
提问于
用户回答回答于

这是正确的,没有catch条款的要求。Oracle java 7 doc表示,无论是否实际抛出异常,资源都将被关闭。

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

以下是Oracle教程的一个片段:

以下示例从文件读取第一行。它使用BufferedReader的一个实例从文件中读取数据。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中的代码执行catchfinally块之后的块。这会导致资源仍然可能在catch块中打开。

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

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

用户回答回答于

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

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仍然关闭。你可以在这里这里找到更多细节。

扫码关注云+社区