stream.spliterator()
是否会隐式关闭stream
,或者之后是否需要明确关闭它?
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 :(得分:10)
终端操作从不关闭流。关闭必须手动完成。自动关闭发生的唯一地方是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?
答案 1 :(得分:4)
关于Java 9中Stream
的关闭没有任何改变。如果应该释放底层资源,你仍然需要手动执行它。你永远不应该依赖垃圾收集器来做到这一点。 docs仍然说:
Streams有一个
BaseStream.close()
方法并实现AutoCloseable
。关闭后在流上操作将抛出IllegalStateException
。大多数流实例实际上不需要在使用后关闭,因为它们由集合,数组或生成函数支持,不需要特殊的资源管理。 通常,只有源为IO通道的流(例如Files.lines(Path)
返回的流)才需要关闭。如果流确实需要关闭,则必须在try-with-resources语句或类似控制结构中将其作为资源打开,以确保在操作完成后立即关闭它。
答案 2 :(得分:4)
对spliterator()
方法的调用会为此流的元素返回 Spliterator
,并其终端操作。
要回答您的问题 - 不,spliterator
方法或为此原因,其他任何终端操作也不会关闭流。
记录为terminal operations作为 -
执行终端操作后,流管道为 考虑消耗,不能再使用....几乎在所有情况下,终端操作 渴望 ,完成对数据源的遍历和 在返回之前处理管道。只有终端 操作
iterator()
和spliterator(
)不是;这些是作为 一个“逃生舱口”,可以实现任意客户控制的管道 如果现有操作不是,则遍历 足以完成任务。
另一方面,在关闭Stream
时,文档声明: -
大多数流实例实际上不需要在使用后关闭,如 它们由集合,数组或生成函数支持 不需要特殊的资源管理。一般来说,只有流 source是一个IO通道,例如
Files.lines(Path)
返回的通道, 将需要关闭。
要匹配的AutoCloseable
州 -
实现基类是可能的,实际上也是常见的 AutoCloseable即使不是它的所有子类或实例也会 持有可释放的资源。
这是BaseStream扩展它的方式,而close()
对使用Files.lines(...)
等资源的流的影响远远大于solution here。
然而,当使用支持两者的Stream等设施时 基于I / O和非I / O的表单,try-with-resources块都在 使用非基于I / O的表单时一般不必要。
答案 3 :(得分:0)
方法stream.spliterator()
不会关闭Stream
,就像没有其他终端操作一样。您可能会或可能不会知道,是否需要关闭Stream
,这仍然是一个很大的争论。我个人希望使用spliterator()
和iterator()
以外的所有终端操作来出于各种原因隐式关闭Stream
。这样做没有什么害处,因为大多数实现都只会执行什么。
您可以在java.util.stream.AbstractPipeline
中找到一种实现。调用stream.onClose(action)
时,将调用调用stream.close()
时添加的关闭动作。
我无法告诉您何时需要显式关闭Stream
,因为当前策略是在返回Stream
的方法(例如Files.list(Path)
)上记录它:
返回的流包含对打开目录的引用。通过关闭流关闭目录。 ...
必须在try-with-resources语句中使用此方法,或者 类似的控制结构,以确保流的打开目录 流的操作完成后,将立即关闭。
调用stream.spliterator()
时,返回的Spliterator
可能很懒(另请参阅AbstractPipeline.lazySpliterator(..)
),因此仍需要对原始Stream
的元素进行操作。如果在遍历Stream
的元素之前关闭Spliterator
,则可能会遇到异常,或者Spliterator
不再起作用。
public static void main(final String[] args) throws IOException {
try (final Stream<Path> stream = Files.list(Paths.get(""))) {
stream.onClose(() -> System.out.println("stream closed"));
final Spliterator<Path> split = stream.spliterator();
/*
* uncomment this to see what happens when you close the
* stream before you traverse the spliterator
*/
// stream.close();
split.forEachRemaining(System.out::println);
}
}
现在的问题是,如果您希望有一个返回Spliterator
的方法,则调用者没有close()
上可以调用的Spliterator
方法。