我需要关闭一个ByteArrayInputStream吗?

56

简短问题,

我看到一些旧代码中创建了一个 ByteArrayInputStream,例如:

new BufferedReader(new InputStreamReader(new ByteArrayInputStream(somebytes)));
然后使用BufferedReader逐行读取somebytes。一切工作正常,但我注意到BufferedReader从未关闭。这在一个长时间运行的WebSphere应用程序中工作,并且somebytes不是非常大(最多200k),每周只调用几次,我们没有遇到任何明显的内存泄漏。因此,我认为所有对象都已成功垃圾回收。 我曾经学过输入/输出流需要在finally语句中关闭。 ByteStreams是否例外?

1
感谢大家的回答和提示!正如下面的评论者所指出的那样,这只是一个RTFM或“你有没有谷歌过?”的问题,因为后者几乎立即揭示了答案。然而据我所知,在stackoverflow上还没有人提出这个问题,而提示是额外的收获。 - dr jerry
4个回答

59

当你不再引用ByteArrayInputStream时,垃圾收集器将释放流和somebytes(当然假设它们在其他地方没有被引用), 所以你不必关闭它。

但是,关闭每个流总是一个好习惯,因为实现创建流的方式可能会在未来改变,而您可能会读取文件而不是原始字节。此外,像PMD或FindBugs(请参见注释)这样的静态代码分析工具很可能会抱怨。

如果你厌倦了关闭流并被迫处理不可能的IOException,你可以使用IOUtils

IOUtils.closeQuietly(stream);

9
FindBugs聪明地不会报告未关闭的BAIS/BAOS。 - MeBigFatGuy
那么,如果Stream / File / Reader / WhateverIoObject超出范围,它会自动关闭吗? - poitroae
如果 ByteArrayInputStream.close() 永远不会抛出 IOException,那么 ByteArrayInputStream.close() 声明 throws IOException 就没有什么好的理由。虽然 InputStream 声明了它会 throws,但是覆盖方法可能只会抛出基类或接口声明异常的子集。所以,Java 实现者要么想保留 ByteArrayInputStream.close() 抛出异常的权利,要么就是他们犯了一个错误。 - Raedwald
我们应该补充一下,自Java 7以来,有try-with-resource这个功能,可以解决大多数情况下需要closeQuietly-utils的问题。 - Tim Büthe
1
IOUtils.closeQuietly(stream)已被弃用。 - Chhorn Elit
显示剩余5条评论

13

关闭读取器一直是一个好的实践。但是不关闭 ByteArrayInputStream 并不会产生太大的潜在负面影响,因为你并没有访问文件,只是在内存中访问字节数组。


6
ByteArrayInputStream的文档会确认close()不会做任何操作。但是最好养成调用流的close()的习惯。您可能会在以后重构代码,使函数接受其他类型的流。 - Nick

3

正如@TomaszNurkiewicz所提到的,关闭已打开的流总是一个好习惯。另一种让它在try块内自行完成的好方法是使用try with resource,例如......

try ( InputStream inputStream = new ByteArrayInputStream(bytes); Workbook workBook = new XSSFWorkbook(inputStream)) { 

在这里,Workbook和InputStream都实现了Closeable接口,所以一旦try块结束(正常或异常),流肯定会被关闭。


我喜欢使用try块,但是你要如何将一个流返回给调用者呢? - pixel

1

需要在 finally(或等效语句)中关闭资源。但如果你只有一些字节,那么这并不重要。尽管如此,在编写时,请注意在正常情况下执行 flush 操作。


2
按设计,close() 必须先刷新。 - bestsss
@bestsss 不管你怎么称呼 flush,也不需要 close。最好还是明确一些。 - Tom Hawtin - tackline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接