为什么在发出终端操作后没有Java close()流?

时间:2015-03-02 15:38:21

标签: java java-8 java-stream

在阅读https://www.airpair.com/java/posts/spring-streams-memory-efficiency之后,我很想将结果从数据库中传出来,但正如我与同事讨论的那样(cfr。评论他添加到那篇文章中),人们需要记住使用try-with -resources构造以避免任何内存泄漏。

  1. 为什么Java 8库不会在每个terminal operation之后关闭流本身(不必在try-with-resources中包装流实例化)?
  2. 如果适用,是否有任何计划将此功能添加到Java中,或者请求它是否有意义?

3 个答案:

答案 0 :(得分:26)

因为需要显式资源释放的流实际上是一个非常不寻常的情况。因此,我们选择不对所有流执行负担,这些内容仅对.01%的使用有价值。

我们制作了Stream Autocloseable,以便您可以从源中释放资源,但这是我们停止的地方,并且有充分的理由。

这样做不仅会使大多数用户自动负担他们不需要的额外工作,而且这也违反了一般原则:分配资源的人负责关闭资源。当你打电话

BufferedReader reader = ...
reader.lines().op().op()...

是打开资源的人,而不是流库,应该关闭它。实际上,由于在某个资源保持对象上调用访问器方法而关闭流有时会关闭底层对象,因此您可能不希望流为您关闭BufferedReader - 您可能希望它电话结束后保持开放状态。

如果要关闭资源,这也很容易:

try (BufferedReader reader = ...) {
    reader.lines().op()...
}

你可能以特定的方式使用流,所以它可能看起来“显而易见”流应该做什么 - 但是有比你更多的用例。因此,我们不是满足于特定用例,而是从一般原则中接近它:如果您打开流,并且希望它关闭,请自行关闭它,但如果您没有打开它,则不能让您关闭。 / p>

答案 1 :(得分:3)

我认为你将java.io.InputStreamjava.util.stream.Stream混合在一起,这是两个非常不同的概念。

try-with-resources适用于实现Autoclosable接口的对象,例如InputStream s。 InputStream代表与IO相关的抽象数据源。

另一方面,

java.util.stream.Stream<T>实现了函数式编程的概念,它代表了一种动态集合,它不一定是静态构建的,而是可以生成,因此可能是无限的。

Marko Topolnik(您链接到的文章的作者)在本文中基本上做了什么,建议将IO源包装到java.util.stream.Stream中。这是一个非常聪明的方法,但java.util.stream.Stream一般不用于此目的。

由于它们通常不适用于IO,因此没有理由在终端操作后包含关闭


修改

在您澄清之后事实上并没有将两者混淆(抱歉这样做),感谢this answer,我发现您的确切示例已在documentation of AutoCloseable中得到解答(自己强调的重点):

  

实现基类是可能的,实际上也是常见的   AutoCloseable即使不是它的所有子类或实例都会   持有可释放的资源。对于必须完整运行的代码   一般性,或者当知道AutoCloseable实例时   需要资源释放,建议使用try-with-resources   结构。 然而,当使用Stream这样的设施时   支持基于I / O和非I / O的表单,try-with-resources   使用非基于I / O的表单时,通常不需要块。

答案 2 :(得分:0)

  

为什么Java 8库不会在每次终端操作后自行关闭流(不必在try-with-resources中包装流实例化)?

因为在终端操作期间或之前可能发生异常,并且您可能不希望终端操作关闭流。如果您确实希望关闭流,可以使用try-with-resource。

  

如果适用,是否有任何计划将此功能添加到Java中,或者请求它是否有意义?

这没有意义,请参阅上面的答案。