我使用StringReader
将字符串转换为可以上传到SFTP服务器的内容(它需要一个流)。之后关闭StringReader
有什么意义吗?据我在源代码中所见,它只是将字符串设置为null
。。。
我可以这么做,但由于close方法被标记为抛出一个IOException
,我所要做的就是用try-catch来包装它,而代码最终看起来比它可能需要的要可怕得多。
如果你知道你要处理的是一个将要丢弃的StringReader
,我看不出有任何理由关闭它。我无法想象在关闭它之后,有什么原因会保留对它的引用,所以将字符串设置为null
进行垃圾收集并没有真正的好处。如果您正在创建一个使用Reader
的方法,那么关闭它可能是有意义的,因为您不知道底层类型。
它的作用不止于此。如果我可以引用JavaDoc:
/**
* Closes the stream and releases any system resources associated with
* it. Once the stream has been closed, further read(),
* ready(), mark(), or reset() invocations will throw an IOException.
* Closing a previously closed stream has no effect.
*/
所以,是的,你应该关闭这个阅读器。不是为了资源,而是为了良好的风格和可能追随你的程序员。你不知道这个实例会被传递到哪里,也不知道其他人会试图用它做什么。有一天你可能会选择更改接口并接受任何Reader实现,在这种情况下,你可能会处理一个需要调用close()来释放资源的Reader。
因此,一旦你完成了这个实例,防止它被进一步(可能是错误的)使用是一种很好的风格。由于它不会造成伤害,它只会防止未来可能出现的错误。
编辑:既然你说你的close()方法正在声明它可能抛出的异常,我想说你需要调用close(。然而,Reader.close()确实如此。所以您已经允许Reader的其他实现,所以您必须关闭它,因为您不知道最终会得到什么Reader实现。如果我们谈论的是从未离开该范围的三行代码,那么声明变量StringReader并无论如何调用close(在这种情况下,没有异常处理)。
尽管严格来说不是必要的,因为StringReader只保存一个字符串,但作为一种良好的形式,关闭所有读卡器总是一个好主意。今天,您的代码可能使用StringReader,但如果您将其更改为另一个真正需要关闭的Reader,则您的代码w/out关闭将是错误的,而您的w/close则可以。
如果变量的类型为StringReader
而不是Reader
,则不需要捕获异常,因为StringReader#close()
不会抛出异常:只有Reader#close()
会抛出异常。因此,您可以使用try-with-resources自动关闭阅读器,而无需使用样板文件来处理不会发生的异常。Reader#close()
抛出IOException
意味着子类型可以抛出这种类型的异常,而不是它们必须。这是一种罕见的情况,您希望用子类型而不是超类型来声明变量;请参阅在java中使用接口或类型进行变量定义?了解更多信息。
因此,我建议如下,它只需要一个级别的嵌套,这与资源相当:
try (StringReader reader = new StringReader(string)) {
// Do something with reader.
}
然而,关闭StringReader
没有什么价值,因为它不包含外部资源(比如说,只有Java托管内存,而不是文件句柄或本机内存),所以省略它是可以的,尽管我建议注释说明为什么这是安全的,因为否则不关闭读卡器是令人惊讶的。正如您所注意到的,close()
只是清空了字段,根据JDK8的源代码:StringReader.java:198。如果你想避免嵌套和关闭,你可以写这样的:
// Don't need to close StringReader, since no external resource.
StringReader reader = new StringReader(string);
// Do something with reader.
或(使用更通用的变量类型):
// Don't need to close StringReader, since no external resource.
Reader reader = new StringReader(string);
// Do something with reader.
正常的资源尝试在这里起作用,因为StringReader#close()
覆盖Reader#close()
,并幸运地声明它不抛出IOException
。
请注意,这不是字符串Writer的情况:StringWriter#close()
确实声明它抛出IOException
,尽管它是nop!这可能是为了前向兼容性,所以它可能会在未来的实现中引发异常,尽管这不太可能。查看我对的回答不关闭字符串写入程序会导致泄漏吗?。
在这种情况下(如果方法没有抛出异常,但接口声明它可以),写这篇文章的最简单方法是:
Reader reader = new StringReader(string);
try {
// Do something with reader, which may or may not throw IOException.
} finally {
try {
reader.close();
} catch (IOException e) {
throw new AssertionError("StringReader#close() cannot throw IOException", e);
}
}
这种级别的样板是必要的,因为你不能只在整个try块上放一个catch,否则你可能会意外地吞下代码体抛出的IOException
。即使目前没有,将来也可能会添加一些,编译器会提醒您注意这一点。还要注意,记录当前行为的AssertionError
也会屏蔽try语句主体引发的异常,尽管这种情况永远不会发生。如果这是另一种选择,那么您最好省略close()
并说明原因。
这个答案取决于您自己创建StringReader
的事实;当然,如果您从其他地方收到Reader
(比如说,作为工厂的返回类型),那么您需要关闭它并处理可能的异常,因为您不知道它可能包含什么资源,它可能会抛出异常。
如果关闭流并释放与之相关的任何系统资源。一旦关闭流,进一步的read()、ready()、mark()或reset()调用将引发IOException。关闭以前关闭的流没有任何效果。指定人:关闭接口关闭指定人:关闭类阅读器