Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do streams stop?

I was wondering when I created my own infinite stream with Stream.generate how the Streams which are in the standard library stop...

For example when you have a list with records:

List<Record> records = getListWithRecords();
records.stream().forEach(/* do something */);

The stream won't be infinite and running forever, but it will stop when all items in the list are traversed. But how does that work? The same functionality applies for the stream created by Files.lines(path) (source: http://www.mkyong.com/java8/java-8-stream-read-a-file-line-by-line/).

And a second question, how can a stream created with Stream.generate be stopped in the same manner then?

like image 946
Juru Avatar asked Feb 05 '16 14:02

Juru


People also ask

How do I stop a stream?

Tap the stream manager and then tap the red End Stream button to end the stream.

Can a stream be infinite?

We can create an infinite stream of any custom type elements by passing a function of a Supplier interface to a generate() method on a Stream.

Why does live stream keep stopping?

Two common reasons for buffering are 1) your internet connection is too slow to stream a video in real time, and 2) the speed at which your router sends the video to all your internet-connected devices is too slow.


1 Answers

Finite streams simply aren’t created via Stream.generate.

The standard way of implementing a stream, is to implement a Spliterator, sometimes using the Iterator detour. In either case, the implementation has a way to report an end, e.g. when Spliterator.tryAdvance returns false or its forEachRemaining method just returns, or in case of an Iterator source, when hasNext() returns false.

A Spliterator may even report the expected number of elements before the processing begins.

Streams, created via one of the factory methods inside the Stream interface, like Stream.generate may be implemented either, by a Spliterator as well or using internal features of the stream implementation, but regardless of how they are implemented, you don’t get hands on this implementation to change their behavior, so the only way to make such a stream finite, is to chain a limit operation to the stream.

If you want to create a non-empty finite stream that is not backed by an array or collection and none of the existing stream sources fits, you have to implement your own Spliterator and create a stream out of it. As told above, you can use an existing method to create a Spliterator out of an Iterator, but you should resists the temptation to use an Iterator just because it’s familiar. A Spliterator is not hard to implement:

/** like {@code Stream.generate}, but with an intrinsic limit */
static <T> Stream<T> generate(Supplier<T> s, long count) {
    return StreamSupport.stream(
               new Spliterators.AbstractSpliterator<T>(count, Spliterator.SIZED) {
        long remaining=count;

        public boolean tryAdvance(Consumer<? super T> action) {
            if(remaining<=0) return false;
            remaining--;
            action.accept(s.get());
            return true;
        }
    }, false);
}

From this starting point, you can add overrides for the default methods of the Spliterator interface, weighting development expense and potential performance improvements, e.g.

static <T> Stream<T> generate(Supplier<T> s, long count) {
    return StreamSupport.stream(
               new Spliterators.AbstractSpliterator<T>(count, Spliterator.SIZED) {
        long remaining=count;

        public boolean tryAdvance(Consumer<? super T> action) {
            if(remaining<=0) return false;
            remaining--;
            action.accept(s.get());
            return true;
        }

        /** May improve the performance of most non-short-circuiting operations */
        @Override
        public void forEachRemaining(Consumer<? super T> action) {
            long toGo=remaining;
            remaining=0;
            for(; toGo>0; toGo--) action.accept(s.get());
        }
    }, false);
}
like image 197
Holger Avatar answered Sep 30 '22 01:09

Holger