我应该关闭StringReader吗?

我使用StringReader将字符串转换为可以上传到SFTP服务器的字符串(它需要一个流)。 之后关闭StringReader有什么意义吗? 据我所知,它只是将字符串设置为null

我可以做到这一点,但是因为close方法被标记为抛出IOException并且所有我必须将它包装在try catch中并且代码最终看起来比它可能需要的更加可怕。

如果你知道你正在处理一个你将丢弃的StringReader ,我认为没有理由关闭它。 在你关闭它之后我无法想象你有什么理由持有它的引用,所以对于垃圾收集设置为null的字符串没有任何实际好处。 如果您正在创建一个带有Reader的方法,那么关闭它可能是有意义的,因为您不知道底层类型。

虽然严格来说没有必要,因为StringReader只保留一个字符串,作为一个良好的forms,它总是一个好主意,无论如何关闭所有读者。 今天你的代码可能正在使用StringReader,但是如果你把它改成另一个真正需要关闭的Reader,你的代码w / out关闭将是错误的,而你的w / close会很好。

它不止于此。 如果我引用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()方法声明一个exception它可能会抛出我会说你需要调用close()因为StringReader.close()不会抛出exception。 但是,Reader.close()可以。 因此,您已经允许其他Reader实现,因此您必须关闭它,因为您无法知道最终将获得哪些Reader实现。 如果我们讨论的是从不离开该范围的三行代码,请声明您的变量StringReader并且无论如何都要调用close(在这种情况下没有exception处理)。

如果您的变量的类型为StringReader而不是Reader ,则不需要捕获exception,因为StringReader#close()不会抛出exception:只有Reader#close()才会发生exception。 因此,您可以使用try-with-resources自动关闭阅读器,而无需使用样板来处理不会发生的exception。 Reader#close()抛出IOException意味着子类型可以抛出这种类型的exception,而不是它们必须抛出的exception。 这是您想要使用子类型而不是超类型声明变量的罕见情况之一; 请参阅在java中使用接口或类型进行变量定义? 更多。

因此,我建议如下,它只需要一个嵌套级别,这是资源的标准:

 try (StringReader reader = new StringReader(string)) { // Do something with reader. } 

但是,关闭StringReader没有什么价值,因为它不包含外部资源(只有Java管理的内存,而不是文件句柄或本机内存,所以),所以可以省略它,尽管我建议一个评论说明为什么这是安全的,因为否则不会关闭读者是令人惊讶的。 正如您所注意到的, close()只是将字段空出来,每个JDK 8源: 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. 

正常的try-with-resources在这里工作,因为StringReader#close()会覆盖Reader#close()并且仁慈地声明它不会抛出IOException

请注意,这不是 String Writer的情况: StringWriter#close() 确实声明它抛出IOException ,尽管它是一个nop! 这可能是为了向前兼容,因此它可能会在未来的实现中引发exception,尽管这不太可能。 看到我的回答 不会关闭字符串写入器导致泄漏? 。

在这种情况下(如果方法没有抛出exception,但界面声明它可以),那么你可能提到的写这个的紧密方法是:

 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语句主体抛出的exception,但这绝不会发生。 如果这是另一种选择,你最好省略close()并评论原因。

这个答案取决于你自己创建StringReader的事实; 当然,如果你从其他地方收到一个Reader (比如工厂的返回类型),那么你需要关闭它并处理可能的exception,因为你不知道它可能拥有什么资源,它可能会抛出例外。

如果关闭流并释放与其关联的任何系统资源。 关闭流后,进一步的read(),ready(),mark()或reset()调用将抛出IOException。 关闭先前关闭的流无效。 指定者:接口中的close Closeable指定者:类Reader中的close