Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the stream.spliterator() close the stream?

Does the stream.spliterator() implicitly closes the stream, or there is a need to explicitly close it afterwards?

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?

At first glance, it seems that the .spliterator() method closes the stream, but without calling stream.close(). At least if I close it straight away after the .spliterator() method is invoked, it seems not affection the spliterator operations.

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

This question can be extended to other stream methods, for example, the .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?

The reason for that question is to have deep clarity when a stream needs explicitly to be closed, and in the cases where I don't need to explicitly close it, when the onClose() defined actions will take place?

like image 417
Tet Avatar asked Oct 11 '17 12:10

Tet


People also ask

What does a Spliterator do?

Spliterator has been introduced in Java 8. It provides support for parallel processing of stream of elements for any collection. It provides tryAdvance() method to iterate elements individually in different threads. It helps in parallel processing.

What is stream Spliterator?

Spliterator is an internal iterator that breaks the stream into the smaller parts. These smaller parts can be processed in parallel.

How does Spliterator work in Java?

It uses forEachRemaining() method to iterate elements sequentially in a single Thread. It uses trySplit() method to divide itself into Sub-Spliterators to support Parallel Processing. Spliterator supports both Sequential and Parallel processing of data.

Do I need to close stream?

Absolutely, by default you should close a stream. A stream is a very generic API; the whole point is that it represents a stream of data without requiring the consumer of that data to understand where the data is coming from.


3 Answers

Terminal operations never close the stream. Closing has to be done manually. The only place where automatic closing happens is within the flatMap operation, where manual closing of the substreams usually created on-the-fly would be somewhere between hard and impossible.

This also applies to the Stream.spliterator() method. In your examples, it makes no difference because the streams created via Stream.of(…) do not need to be closed and have no onClose() operation registered by default.

You have to consult the documentation of the factory methods to find out when a stream need to be closed. E.g. like Files#lines(Path, Charset).

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

like image 186
Holger Avatar answered Oct 02 '22 16:10

Holger


Nothing changed concerning the closing of Streams in Java 9. You still need to manually do it if the underlying resource should be freed. You should never rely on the garbage collector to do it. The docs still say:

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.

like image 22
M A Avatar answered Oct 02 '22 15:10

M A


The call to spliterator() method returns a Spliterator for the elements of this stream and its a terminal operation.

To answer your question - No, the spliterator method or for that sake none of the other terminal operations also does not close the stream.

This stands documented for terminal operations as -

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.

Over closing the Stream on another hand the docs state that:-

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.


The AutoCloseable states to match to it-

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.

which is how the BaseStream extends it and the close() doesn't impact far more than the streams over the ones using the resources such as 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.

like image 34
Naman Avatar answered Oct 02 '22 15:10

Naman