stream.spliterator() 是否关闭流?

Does the stream.spliterator() close the stream?

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()将执行定义的操作?

Java9 中 Stream 的关闭没有任何变化。如果要释放底层资源,您仍然需要手动执行此操作。你永远不应该依赖垃圾收集器来做这件事。 docs 还是说:

Streams have a BaseStream.close() method and implement AutoCloseable. Operating on a stream after it has been closed will throw IllegalStateException. Most stream instances do not actually need to be closed after use, as they are backed by collections, arrays, or generating functions, which require no special resource management. Generally, only streams whose source is an IO channel, such as those returned by Files.lines(Path), will require closing. If a stream does require closing, it must be opened as a resource within a try-with-resources statement or similar control structure to ensure that it is closed promptly after its operations have completed.

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

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

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

另见 or Does Java 8 Stream.iterator() auto-close the stream when it's done?

为此流的元素调用 spliterator() method returns a Spliterator它是一个终端操作。

回答你的问题 - 不,其他 终端操作 spliterator 方法或为此目的 none 也不 关闭 流。

这代表 terminal operations 记录为 -

After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer be used.... In almost all cases, terminal operations are eager, completing their traversal of the data source and processing of the pipeline before returning. Only the terminal operations iterator() and spliterator() are not; these are provided as an "escape hatch" to enable arbitrary client-controlled pipeline traversals in the event that the existing operations are not sufficient to the task.

另一方面,关闭 Stream 文档指出:-

Most stream instances do not actually need to be closed after use, as they are backed by collections, arrays, or generating functions, which require no special resource management. Generally, only streams whose source is an IO channel, such as those returned by Files.lines(Path), will require closing.


AutoCloseable 状态匹配它-

It is possible, and in fact common, for a base class to implement AutoCloseable even though not all of its subclasses or instances will hold releasable resources.

这就是 BaseStream 对其进行扩展的方式,close() 的影响远不及使用 Files.lines(...).

等资源的流

However, when using facilities such as Stream that support both I/O-based and non-I/O-based forms, try-with-resources blocks are in general unnecessary when using non-I/O-based forms.

方法stream.spliterator()不会关闭Stream,就像没有其他终端操作一样。您可能知道也可能不知道,如果您需要关闭 Stream,那仍然是一个很大的争论。由于各种原因,我个人希望除了 spliterator()iterator() 之外的所有终端操作都隐式关闭 Stream。这样做没有什么坏处,因为大多数实现只会做 nothing.

您可以在 java.util.stream.AbstractPipeline 中找到一种实现。调用stream.onClose(action)时添加的关闭动作将在调用stream.close()时调用。

我不能告诉你什么时候 Stream 明确需要关闭,因为当前的政策是在 returns 和 Stream 的方法上记录它,比如 [=22] =]:

The returned stream contains a reference to an open directory. The directory is closed by closing the stream. ...

This method must be used within a try-with-resources statement or similar control structure to ensure that the stream's open directory is closed promptly after the stream's operations have completed.

当你调用stream.spliterator()时,返回的Spliterator可能是惰性的(参见AbstractPipeline.lazySpliterator(..)),因此仍然需要对原始Stream的元素进行操作.如果在遍历 Spliterator 的元素之前关闭 Stream,您可能会遇到异常,或者 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);
    }
}

现在的问题是,如果你想要returns一个Spliterator的方法,调用者没有close()可以在[=24=上调用的方法].