流如何停止? [英] How do streams stop?

查看:25
本文介绍了流如何停止?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道当我使用 Stream.generate 创建自己的无限流时,标准库中的流如何停止...

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 */);

流不会是无限的并且永远运行,但是当遍历列表中的所有项目时它会停止.但这是如何工作的?相同的功能适用于 Files.lines(path) 创建的流(来源:http://www.mkyong.com/java8/java-8-stream-read-a-file-line-by-line/).

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/).

第二个问题,如何以同样的方式停止使用 Stream.generate 创建的流?

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

推荐答案

有限流根本不是通过 Stream.generate 创建的.

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

实现流的标准方法是实现 Spliterator,有时使用 Iterator绕道.在任何一种情况下,实现都有一种方法来报告结束,例如当 Spliterator.tryAdvance 返回 false 或其 forEachRemaining 方法仅返回时,或者在 Iterator 源的情况下,当hasNext() 返回 false.

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.

Spliterator 甚至可以在处理开始之前报告预期的元素数量.

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

Streams,通过 Stream 接口内的一种工厂方法创建,例如 Stream.generate 可以由 Spliterator 实现也可以使用流实现的内部功能,但无论它们是如何实现的,您都无法通过此实现来改变它们的行为,因此使这种流有限的唯一方法是链接 限制对流的操作.

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.

如果你想创建一个非空的有限流,它不受数组或集合的支持,并且现有的流源都不适合,你必须实现自己的 Spliterator从中创建一个流.如上所述,您可以使用现有方法从 Iterator 中创建 Spliterator,但您应该抵制使用 Iterator 的诱惑只是因为熟悉.Spliterator 并不难实现:

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);
}

从这个起点,您可以为 Spliterator 接口的 default 方法添加覆盖,权衡开发费用和潜在的性能改进,例如

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);
}

这篇关于流如何停止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆