java 不关闭字符串编写器会导致泄漏吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14542535/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Will not closing a stringwriter cause a leak?
提问by Blankman
I realize that in java the GC will eventually cleanup objects, but I'm asking if it is bad practice to not close your string writer, currently I am doing this:
我意识到在 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();
}
Should I be closing the writer and creating a new String like this:
我应该关闭作者并创建一个像这样的新字符串:
String result = "";
...
finally {
result = writer.toString();
writer.close();
}
Is this better to do?
这样做更好吗?
回答by assylias
回答by James Curran
It's not holding any non-memory resource. It will be garbage collected like anything else. The close() probabaly merely exists because other writer objects do hold resources that need to be cleaned up, and the close() is needed to satify the interface.
它不持有任何非内存资源。它将像其他任何东西一样被垃圾收集。close() 可能只是因为其他编写器对象确实持有需要清理的资源而存在,并且需要 close() 来满足接口。
回答by Nils von Barth
No, not closing a StringWriter
will not cause a leak: as noted, StringWriter#close()
is a nop, and the writer only holds memory, not external resources, so these will be collected when the writer is collected. (Explicitly, it holds references to objects in private fields that do not escape the object, concretely a StringBuffer
, so no outside references.)
不,不关闭 aStringWriter
不会导致泄漏:如前所述,StringWriter#close()
是一个 nop,并且写入者只持有内存,而不是外部资源,因此在收集写入者时将收集这些。(明确地,它在不转义对象的私有字段中保存对对象的引用,具体来说是 a StringBuffer
,因此没有外部引用。)
Further, you generally shouldn'tclose a StringWriter
, because it adds boilerplate to your code, obscuring the main logic, as we'll see. However, to reassure readers that you're being careful and doing this intentionally, I'd recommend commenting this fact:
此外,您通常不应该关闭 a StringWriter
,因为它会向您的代码添加样板文件,从而掩盖了主要逻辑,正如我们将看到的。但是,为了让读者放心,您是小心谨慎的并且是故意这样做的,我建议您评论以下事实:
// Don't need to close StringWriter, since no external resource.
Writer writer = new StringWriter();
// Do something with writer.
If you do want to close the writer, most elegant is to use try-with-resources, which will automatically call close()
when you exit the body of the try block:
如果您确实想关闭编写器,最优雅的是使用try-with-resources,它会close()
在您退出 try 块的主体时自动调用:
try (Writer writer = new StringWriter()) {
// Do something with writer.
return writer.toString();
}
However, since Writer#close()throws IOException
, your method now needs to also throw IOException
even though it never occurs, or you need to catch it, to prove to the compiler that it is handled. This is quite involved:
但是,由于Writer#close()throws 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);
}
}
This level of boilerplate is necessary because you can't just put a catch on the overall try block, as otherwise you might accidentally swallow an IOException
thrown by the body of your code. Even if there isn't any currently, some might be added in future and you'd want to be warned of this by the compiler. The AssertionError
is documenting the current behavior of StringWriter#close()
, which could potentially change in a future release, though that is extremely unlikely; it also masks any exception that may occur in the body of the try (again, this should never occur in practice). This is far too much boilerplate and complexity, and you'd clearly be better off omitting the close()
and commenting why.
这种级别的样板是必要的,因为您不能只在整个 try 块上放置一个捕获,否则您可能会不小心吞下IOException
代码主体抛出的一个。即使目前没有,将来也可能会添加一些,并且您希望编译器对此发出警告。本AssertionError
是记录的当前行为StringWriter#close()
,这可能在未来的版本中可能会更改,虽然这是极不可能的; 它还掩盖了 try 主体中可能发生的任何异常(同样,这在实践中永远不应该发生)。这是太多的样板和复杂性,你显然最好省略close()
和评论为什么。
A subtle point is that not only does Writer#close()
throw an IOException
, but so does StringWriter#close()
, so you can't eliminate the exception by making the variable a StringWriter
instead of a Writer
. This is differentfrom StringReader, which overrides the close()
method and specifies that it does notthrow an exception! See my answerto Should I close a StringReader?. This may look wrong – why would you have a method that does nothing but may throw an exception?? – but is presumably for forward compatibility, to leave open the possibility of throwing an IOException
on close in future, as this is an issue for writers generally. (It could also just be a mistake.)
一个微妙的一点是,不仅Writer#close()
抛出 an IOException
,而且抛出StringWriter#close()
,因此您无法通过将变量 aStringWriter
而不是a来消除异常Writer
。这与 String Reader不同,后者覆盖方法并指定不抛出异常!请参阅我对我应该关闭 StringReader 的回答吗?. 这看起来可能是错误的——为什么你会有一个什么都不做但可能会抛出异常的方法?– 但大概是为了向前兼容,保留将来关闭的可能性,因为这通常是作家的问题。(这也可能只是一个错误。)close()
IOException
To summarize: it's fine to not close a StringWriter
, but the reason to not do the usual right thing, namely try-with-resources, is just because close()
declares that it throws an exception that it doesn't actually throw in practice, and handling this precisely is a lot of boilerplate. In any other case it's better to just use the conventionally correct resource-management pattern and prevent problems and head-scratching.
总结一下:不关闭 a 很好StringWriter
,但不做通常正确的事情的原因,即 try-with-resources,只是因为close()
声明它抛出了一个实际上实际上并没有抛出的异常,并处理了这个恰恰是很多样板。在任何其他情况下,最好只使用传统上正确的资源管理模式并防止出现问题和头疼。
回答by MrSmith42
At the end of the method there is no reference left to the writer
therefore it will be freed by the GC.
在方法结束时,没有对 的引用,writer
因此它将被 GC 释放。