溪流如何停止?

Jur*_*uru 8 infinite java-8 java-stream

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

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

List<Record> records = getListWithRecords();
records.stream().forEach(/* do something */);
Run Code Online (Sandbox Code Playgroud)

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

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

Hol*_*ger 13

有限流简直不是通过创建的Stream.generate.

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

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

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

如果要创建一个没有数组或集合支持的非空有限流,并且没有任何现有流源适合,则必须实现自己的流Spliterator并从中创建流.正如上面说,你可以使用现有的方法来创建Spliterator出来的Iterator,但你应该抵制使用一个诱惑Iterator,因为它是熟悉而已.A Spliterator并不难实现:

/** 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

  • `BufferedReader.lines()`就是一个很好的例子.看看`next()`和[`hasNext()`的实现(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/io /BufferedReader.java?av=f#566)以及他们如何在调用之间保持状态.相比之下,分裂器是直截了当的,需要一种方法:`tryAdvance(Consumer <?super String> c){String line = readLine(); if(line == null)返回false; c.accept(线); 返回true; 那就是它.更容易实现(添加异常处理,仍然是代码大小的一半),不需要包装器...... (5认同)