2017-10-11 110 views
10

stream.spliterator()是否隐式关闭了stream,或者需要在之后明确关闭它?stream.spliterator()是否关闭流?

Stream<String> stream = Stream.of("a", "b", "c"); 
Spliterator<T> spliterator = stream.spliterator(); 
// Some low lever operation with the spliterator 
stream.close(); // do we need to close? 

乍一看,似乎.spliterator()方法关闭stream,但没有叫stream.close()。至少如果我在调用.spliterator()方法后马上关闭它,似乎不会影响分割器的操作。

Stream<String> stream = Stream.of("a", "b", "c").limit(2); 
Spliterator<T> spliterator = stream.spliterator(); 
stream.close(); 
// Some low lever operation with the spliterator 

这个问题可以被扩展到其它stream方法,例如,该.findAny()

stream.findAny() // Can I assume that I don't need to close the stream? 
stream.onClose(() -> System.out.println("hi!")).findAny()` 
// when the `onClose()` action will be called? 

原因这个问题是有深刻的清晰度当stream需要明确地关闭,在我并不需要明确地关闭它的情况下,当onClose()定义的动作将发生?

+0

Stream接口扩展了AutoCloseable接口,所以我在guest垃圾收集器处理流时会调用'onClose'动作。但最好尽快关闭它。 – Tet

+4

不,没有垃圾收集器驱动关闭流 - 如果流有这样一个终结器,结果将是灾难性的。底层资源本身*可能*具有自动清理,但取决于资源。但这并不意味着执行任何注册到流中的关闭处理程序。 – Holger

+2

只是为了增加细节,这里是一个很好的洞察流和[TWR斯图尔特](https://stackoverflow.com/a/22929990/1746118) – nullpointer

回答

8

终端操作做从来没有关闭流。关闭必须手动完成。唯一发生自动关闭的地方是在flatMap操作中,手动关闭通常在运行中创建的子流将介于困难和不可能之间。

这也适用于Stream.spliterator()方法。在你的例子中,它没有区别,因为通过Stream.of(…)创建的流不需要关闭,并且没有onClose操作默认注册。

您必须查阅工厂方法的文档以确定何时需要关闭流,例如,像Files#lines(Path, Charset)一样。

参见Does collect operation on Stream close the stream and underlying resources?Does Java 8 Stream.iterator() auto-close the stream when it's done?

+0

感谢@Holger,如果终端操作使流处于不可用状态(例如'.findAny()'),那么为什么在返回值之前终端操作没有关闭流? – Tet

+2

@Tet:遵循关闭的责任在于资源的创建者和终端操作没有分配资源的原则。同样,当您读取最后一个字节时,'InputStream'不会自动关闭。 – Holger

4

关于在Java 9中关闭Stream s,没有什么变化。如果底层资源应该被释放,您仍然需要手动执行此操作。你不应该依赖垃圾收集器来做到这一点。该docs仍然说:

流有BaseStream.close()方法和实施AutoCloseable。在关闭后在流上操作将抛出IllegalStateException。大多数流实例实际上并不需要在使用后关闭,因为它们受集合,数组或生成函数的支持,不需要特殊的资源管理。 通常,只有源数据流为IO通道的数据流(例如Files.lines(Path)返回的数据流)需要关闭。如果流确实需要关闭,则必须在try-with-resources语句或类似的控制结构中将其作为资源打开,以确保在其操作完成后立即关闭它。

5

spliterator()方法的调用返回一个Spliterator此流的元件和其的终端的操作。

要回答你的问题 - 不,spliterator方法或为缘故没有其他终端操作也不会接近流。

这代表对文件作为terminal operations -

进行终端操作之后,流管道 视为消耗,可以不再使用....几乎在所有的情况下,终端操作 都是渴望,完成它们遍历的数据源和 在返回之前处理管道。只有终端 操作iterator()spliterator(不是;这些是作为 作为“逃生舱口”提供的,以便在任何足以执行任务的现有操作不是 的情况下,允许任意客户端控制的管线穿越 。

在对另一只手关闭Stream的文档指出: -

大部分流实例实际上并不需要使用后关闭,因为 它们被集合为后盾,阵列,或发生功能,其中 不需要特殊的资源管理。一般来说,只有源码为IO通道的数据流(例如Files.lines(Path), 返回的数据流)需要关闭。


AutoCloseable状态以匹配IT-

这是可能的,而且实际上很常见的,一个基类来实现 AutoCloseable即使不是所有它的子类或实例将 持有可释放资源。

这是怎么BaseStream扩展它和close()不会影响不是通过使用资源,如Files.lines(...)的那些流远不止这些。

然而,利用设施,如流同时支持 I/O型和非I/O类表单时,尽量与 - 资源块是 一般不需要使用时,非I /基于O的表单。