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?
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.
Spliterator is an internal iterator that breaks the stream into the smaller parts. These smaller parts can be processed in parallel.
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.
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.
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?
Nothing changed concerning the closing of Stream
s 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 implementAutoCloseable
. Operating on a stream after it has been closed will throwIllegalStateException
. 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 byFiles.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.
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()
andspliterator(
) 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With