不会关闭字符串打字机会导致泄漏?
我意识到,在Java中GC将最终清理对象,但我问是不是关闭你的字符串编写器是不好的做法,目前我正在这样做:
private static String processTemplate(final Template template, final Map root) {
StringWriter writer = new StringWriter();
try {
template.process(root, writer);
} catch (TemplateException e) {
logger.error(e.getMessage());
} catch (IOException e) {
logger.error(e.getMessage());
}
finally {
}
return writer.toString();
}
我应该关闭作家并创建一个像这样的新字符串:
String result = "";
...
finally {
result = writer.toString();
writer.close();
}
这更好吗?
javadoc非常明确:
关闭StringWriter不起作用。
快速浏览代码证实了这一点:
public void close() throws IOException {
}
它不包含任何非内存资源。 它将像其他任何垃圾一样被收集起来。 close()可能性仅仅存在,因为其他作者对象确实需要清理资源,并且需要close()来满足接口。
不,不关闭StringWriter
不会导致泄漏:如上所述, StringWriter#close()
是一个nop,并且作者只保存内存,而不是外部资源,因此在收集作者时会收集这些内容。 (明确地说,它保存私有字段中不会转义对象的对象的引用,具体而言是一个StringBuffer
,因此没有外部引用。)
此外,你通常不应该关闭一个StringWriter
,因为它会给你的代码添加样板,掩盖了主逻辑,正如我们将会看到的那样。 然而,为了让读者放心,你小心谨慎地做这件事,我建议评论一下这个事实:
// Don't need to close StringWriter, since no external resource.
Writer writer = new StringWriter();
// Do something with writer.
如果你想关闭这个编写器,最优雅的是使用try-with-resources,当你退出try块的主体时它会自动调用close()
:
try (Writer writer = new StringWriter()) {
// Do something with writer.
return writer.toString();
}
但是,由于Writer#close()抛出IOException
异常,因此您的方法现在还需要抛出IOException
即使它永远不会发生,或者您需要捕获它,以向编译器证明它已被处理。 这涉及很多:
Writer writer = new StringWriter();
try {
// Do something with writer, which may or may not throw IOException.
return writer.toString();
} finally {
try {
writer.close();
} catch (IOException e) {
throw new AssertionError("StringWriter#close() should not throw IOException", e);
}
}
这样的样板级别是必需的,因为您不能只在整个try块上放一个catch,否则可能会意外地吞下代码主体抛出的IOException
。 即使目前还没有,有些可能会在未来添加,您希望编译器提醒您。 AssertionError
记录了StringWriter#close()
的当前行为,该行为在未来的版本中可能会发生变化,尽管这是不太可能的; 它也掩盖了尝试主体中可能发生的任何异常(同样,这在实践中绝不会发生)。 这是太多的样板和复杂性,你最好省略close()
和评论原因。
微妙的一点是, Writer#close()
不仅会抛出IOException
,而且StringWriter#close()
也会抛出异常,因此您无法通过将该变量设置为StringWriter
而不是Writer
来消除该异常。 这与StringReader不同,它重写close()
方法并指定它不会抛出异常! 查看我的答案我应该关闭一个StringReader吗? 这可能看起来错了 - 为什么你会有一个什么都不做,但可能会抛出异常的方法? - 但大概是为了向前兼容,在将来会留下抛出IOException
的可能性,因为这对于作者来说通常是个问题。 (这也可能只是一个错误。)
总结一下:不关闭StringWriter
,但是不做正常事情的原因,就是try-with-resources,只是因为close()
声明抛出了一个实际上并没有抛出的异常,并且正确地处理这是很多样板。 在任何其他情况下,最好只使用传统上正确的资源管理模式,并防止出现问题和头疼。