1

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

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

我一直使用以下风格:

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

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

4

6 回答 6

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
}

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

于 2012-08-30T14:58:39.330 回答
0

假设在第一个示例中,您在定义之前有一些其他代码可以让您退出 try 块。如果您在未定义的情况下到达 finally,您将在尝试关闭它时收到 NullPointerException。因此,您必须进行检查以避免此类错误。

于 2012-08-30T14:56:53.277 回答
0

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

in.close();

在try/catch 块之外的第二个块中:

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

在进入块之前很容易遇到其他异常并且InputStream永远不会关闭。

于 2012-08-30T14:57:36.800 回答
0

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

另一个常见的习惯用法是编写一个closeQuietly()方法来避免必须if (is != null)在你的finally块上写检查。这就是 Apache CommonIOUtils所做的:

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) { 
}
于 2012-08-30T15:01:27.663 回答
0

InputStream这是一个非常简单的示例,并且可能不会像您在同一个人中创建那样造成问题。但是如果InputStream由于Exception or其他故障而关闭,在这种情况下您的代码将失败,因此最好检查是否InputStream可用

于 2012-08-30T15:05:48.773 回答
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打开失败,你将进入 finally 块,并且只释放in- 因为out==null.

编辑

正如 aetheria 所提到的,该代码无法正常工作,因为close()在 Java 中会引发异常。它可以通过将每个资源释放放在它自己的块中来轻松try修复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){}
}

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

现在,aetheria 还建议为每个资源放置一个单独的try-finally块,如下所示:

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

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

于 2012-08-30T15:17:46.860 回答