在Java 1.6中清理资源的首选方法

时间:2012-08-30 14:54:09

标签: java idioms

我经常看到这种资源清理方式:

InputStream in = null;
try {
    in = new FileInputStream(file);
    // ...
} finally {
    if (in != null) {
        in.close();
    }
}

我一直使用以下风格:

final InputStream in = new FileInputStream(file);
try {
    // ...
} finally {
    in.close();
}

但我错过了什么吗?我没有看到前者的优势吗?

6 个答案:

答案 0 :(得分:1)

我怀疑它避免使用两个嵌套的try / catch块而不是一个。

InputStream in = null;
try {
    in = new FileInputStream(file);
    // ...
} catch(IOException ioe) {
    // handle exception.
} finally {
    IOUtils.closeQuietly(in);
}

第二种情况不完整。

try {
    final InputStream in = new FileInputStream(file);
    try {
        // ...
    } finally {
        in.close();
    }
} catch(IOException e) {
    // handle exception
}

如果您有多个文件,这可能会非常混乱。

答案 1 :(得分:0)

假设在第一个示例中,在定义 in 之前,您还有一些其他代码可以让您退出try块。如果你在没有定义的情况下进入finally,那么在尝试关闭它时会得到NullPointerException。所以你必须进行检查以避免这样的错误。

答案 2 :(得分:0)

此处null的{​​{1}}检查是必要的,因为可能无法分配变量。在这种情况下,在调用时尝试关闭它时会抛出NullPointerException:

InputStream

在try / catch块的第二个块 outside 中:

in.close();

在进入区块之前,您可以轻松地遇到其他例外,final InputStream in = new FileInputStream(file); try { // ... } finally { in.close(); } 永远不会关闭。

答案 3 :(得分:0)

第二个不会编译,因为FileInputStream的构造函数可以抛出FileNotFoundException,因此你需要一个额外的try-catch块,除非当然方法本身抛出它

另一个常见的习惯是编写closeQuietly()方法,以避免在if (is != null)块上编写finally检查。这就是Apache Common的IOUtils所做的:

public static void closeQuietly(InputStream input) {
  try {
    if (input != null) {
      input.close();
    }
  } catch (IOException ioe) {
    // ignore
  }
}

另请注意 Java 7以来,您可以使用以下内容:

try (InputStream is = new FileInputStream(file)) {
} catch (final FileNotFoundException | IOException ex) { 
}

答案 4 :(得分:0)

这是一个非常简单的示例,并且在您在同一个bloke中创建InputStream时可能不会产生问题。但是如果由于某些InputStream其他错误导致Exception or关闭,那么您的代码将失败,因此最好检查InputStream是否可用

答案 5 :(得分:0)

让我们说你需要打开一个而不是两个文件。你会做的

final InputStream in = new FileInputStream(file1);
final OutputStream out = new FileOutputStream(file2);
try {
    // ...
} finally {
    out.close();
    in.close();
}

如果out无法打开,您将收到异常,因为try阻止in阻止finally阻止InputStream in = null; OutputStream out = null; try { in = new FileInputStream(file1); out = new FileOutputStream(file2); // ... } finally { if (out != null) out.close(); if (in != null) in.close(); } 阻止。

在另一种方法中:

out

如果finally无法打开,您将转到in块并关闭两个流。如果in无法打开,您将转到finally块,并且仅免费out==null - 因为close()

修改

正如所提到的aetheria,该代码不起作用,因为try在Java中抛出异常。可以通过将每个资源版本放入其自己的catch - InputStream in = null; OutputStream out = null; try { in = new FileInputStream(file1); out = new FileOutputStream(file2); // ... } finally { try{ out.close(); }catch(Exception e){} try{ in.close(); }catch(Exception e){} } 块中来轻松修复:

in

我放弃了空检查 - 如果outNullPointerException为空,则会抛出一个将被忽略的close。我忽略finally例外的原因是处理方法不应该首先抛出异常。如果需要处理结束例外,您可以再次关闭流, close块之后。这样,可以关闭的任何流都将被关闭(因此您不必担心它),并且您可以更优雅地处理来自try的任何异常。

现在,aetheria还建议为每个资源添加一个单独的finally - final InputStream in = new FileInputStream(file1); try { final OutputStream out = new FileOutputStream(file2); try { // ... } finally { out.close(); } } finally { in.close(); } 块,如下所示:

{{1}}

这很有效,但即使只有两个资源,它也不那么优雅,因为它会分配分配并释放代码,这使得跟踪它变得更加困难(至少在我看来)。