当只使用一个 AutoCloseable
资源时,Java7尝试使用资源语法(也称为 ARM 块(自动资源管理))是漂亮、简短和直接的。然而,当我需要声明多个相互依赖的资源时,我不确定什么是正确的习惯用法,例如一个 FileWriter
和一个包装它的 BufferedWriter
。当然,这个问题涉及到包装某些 AutoCloseable
资源的任何情况,而不仅仅是这两个特定的类。
我提出了以下三种选择:
我看到的一个简单的习惯做法是在 ARM 管理的变量中仅声明顶级包装器:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
这个又短又好,但是坏了。因为底层的 FileWriter
没有在变量中声明,所以它永远不会在生成的 finally
块中直接关闭。只有通过包装 BufferedWriter
的 close
方法,它才会被关闭。问题是,如果从 bw
的构造函数抛出异常,则不会调用它的 close
,因此也不会调用底层的 FileWriter
将不会关闭。
static void printToFile2(String text, File file) {
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
在这里,底层资源和包装资源都是在 ARM 管理的变量中声明的,因此它们肯定都是关闭的,但是底层 fw.close()
将被召唤两次: 不仅直接关闭,而且还通过包装 bw.close()
关闭。
对于这两个同时实现 Closeable
(它是 AutoCloseable
的子类型)的特定类来说,这应该不成问题,因为它们的协议规定允许对 close
进行多次调用:
关闭此流并释放与其关联的任何系统资源。如果流已经关闭,那么调用此方法将无效。
但是,在一般情况下,我可以拥有只实现 AutoCloseable
(而不是 Closeable
)的资源,这并不能保证 close
可以被多次调用:
注意,与 java.io 的 close 方法不同。可闭的,这个闭方法不需要是幂等的。换句话说,多次调用这个 close 方法可能会产生一些可见的副作用,不像 Closeable.close,如果多次调用则不会产生任何效果。但是,强烈建议该接口的实现者使其 close 方法等幂。
static void printToFile3(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
这个版本在理论上应该是正确的,因为只有 fw
表示需要清理的实际资源。bw
本身不包含任何资源,它只委托给 fw
,因此只关闭底层的 fw
就足够了。
另一方面,语法有点不规则,而且 Eclipse 发出了一个警告,我认为这是一个错误的警告,但它仍然是一个必须处理的警告:
资源泄漏: “ bw”永远不会关闭
那么,我该用哪种方法呢? 还是我错过了一些其他的成语,那就是 正确1?