不会关闭一个字符串写入器导致泄漏?

时间:2013-01-26 23:11:54

标签: java memory-management freemarker stringwriter

我意识到在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:

String result = "";

...

finally {
  result = writer.toString();
  writer.close();
}

这样做会更好吗?

4 个答案:

答案 0 :(得分:67)

javadoc非常明确:

  

关闭StringWriter无效。

快速查看the code证实了这一点:

public void close() throws IOException {
}

答案 1 :(得分:4)

它没有持有任何非内存资源。它将像其他任何东西一样被垃圾收集。 close()probabaly仅存在,因为其他编写器对象确实拥有需要清理的资源,并且需要close()来满足界面。

答案 2 :(得分:2)

不,不关闭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块进行捕获,否则你可能会意外地吞下代码正文所引发的IOException。即使目前还没有,也可能会在将来添加一些,并且您希望编译器对此进行警告。 AssertionError正在记录StringWriter#close()的当前行为,这可能会在将来的版本中发生变化,尽管这种可能性极小;它还掩盖了在try的主体中可能发生的任何异常(同样,这在实践中永远不会发生)。这是太多的样板和复杂性,你最好省略close()并评论原因。

一个微妙的问题是,Writer#close()不仅会IOException,而且会StringWriter#close(),因此您无法通过使变量成为{{{{}}来消除异常。 1}}而不是StringWriter。这是来自String Reader 不同,它会覆盖Writer方法并指定它抛出异常!见my answerShould I close a StringReader?。这可能看起来不对 - 为什么你会有一个方法什么都不做,但可能会抛出异常? - 但可能是为了向前兼容,留下将来close()关闭的可能性,因为这通常是作家的问题。 (这也可能只是一个错误。)

总结一下:没有关闭IOException是没关系的,但不做通常正确的事情的原因,即try-with-resources,只是因为StringWriter声明了它引发了一个例外,它实际上并没有实际抛出,并且正确处理这个问题是很多样板。在任何其他情况下,最好只使用传统正确的资源管理模式,防止出现问题和头疼。

答案 3 :(得分:0)

在方法结束时,writer没有任何参考,因此它将被GC释放。