我意识到,在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();
}
号
这样做更好吗?
另请参见StringReader的相应问题:我应该关闭StringReader吗?.
JavaDoc非常明确:
Closing a StringWriter has no effect.
号
快速查看代码就可以确认:
public void close() throws IOException {
}
什么都不做,扔了IOException的close()。
它没有任何非内存资源。它将像其他任何东西一样被垃圾收集。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);
}
}
。
这一级别的样板文件是必要的,因为您不能将catch放在整个try块上,否则您可能会意外地吞下代码体抛出的IOException。即使当前没有,将来也可能会添加一些,编译器会警告您这一点。AssertionError正在记录StringWriter#close()的当前行为,该行为可能在将来的版本中发生变化,尽管这是极不可能的;它也掩盖了在尝试体中可能发生的任何异常(同样,这在实践中不应该发生)。这是太多的样板文件和复杂性,显然您最好省略close()并评论原因。
一个微妙的点是,不仅Writer#close()抛出了IOException,StringWriter#close()也抛出了IOException,所以不能通过将变量设置为StringWriter而不是writer来消除异常。这与StringReader不同,它重写close()方法并指定不引发异常!看到我的答案了,我应该关闭一个字符串阅读器吗?。这可能看起来是错误的–为什么您会有一个方法,它只会抛出异常??—但这可能是为了向前兼容,为以后在关闭时抛出一个IOException留出了可能性,因为这通常是作者面临的问题。(这也可能是一个错误。)
总而言之:不关闭一个StringWriter是可以的,但是不做通常正确的事情的原因,即尝试使用资源,仅仅是因为close()声明它抛出了一个异常,实际上它并没有抛出,而处理这个异常则是一个很大的样板。在任何其他情况下,最好只是使用传统的正确的资源管理模式,防止问题和头疼。
在方法的末尾,没有对writer的引用,因此GC将释放它。