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

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

问题描述

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



例如,如果您有一个包含记录的列表:

  List< Record> records = getListWithRecords(); 
records.stream()。forEach(/ *做某事* /);

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



第二个问题,如何使用 Stream.generate 然后以相同的方式停止?

解决方案

有限流不是通过 Stream创建的。生成



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



A Spliterator 甚至可以在处理开始前报告预期的元素数量。 / p>

Streams,通过 Stream 界面中的一种工厂方法创建,如 Stream。生成也可以通过 Spliterator 或使用流实现的内部功能来实现,但不管它们是如何实现的,不要让这个实现改变他们的行为,所以使这样的流有限的唯一方法是将限制操作链接到流。



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

  / ** like { @code Stream.generate},但具有内在限制* / 
static< T>流< T>生成(供应商< T> s,长计数){
返回StreamSupport.stream(
new Spliterators.AbstractSpliterator< T>(count,Spliterator.SIZED){
long remaining = count;

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

从这个起点开始,你可以为默认 Spliterator 界面的方法,加权开发费用和潜在的性能改进,例如

  static< T>流< T>生成(供应商< T> s,长计数){
返回StreamSupport.stream(
new Spliterators.AbstractSpliterator< T>(count,Spliterator.SIZED){
long remaining = count;

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

/ **可以改善大多数非短路操作的性能* /
@Override
public void forEachRemaining(Consumer<?super T> action){
long toGo =剩余;
剩余= 0;
for(; toGo> 0; toGo--)操作.accept(s.get());
}
},false);
}


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?

解决方案

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

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

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