Java中有限生成的流 - 如何创建一个?

时间:2016-03-16 22:10:04

标签: java java-8 java-stream

在Java中,可以使用Stream.generate(supplier)轻松生成无限流。但是,我需要生成一个最终会完成的流。

想象一下,例如,我想要一个目录中所有文件的流。文件数量可能很大,因此我无法预先收集所有数据并从中创建流(通过collection.stream())。我需要逐个生成序列。但是流显然会在某个时刻完成,终端运营商(collect()findAny())需要对其进行处理,因此Stream.generate(supplier)不适用于此。

有没有合理的简单方法在Java中执行此操作,而不是自己实现整个Stream接口?

我可以想到一个简单的黑客 - 使用无限Stream.generate(supplier)执行此操作,并在获取所有实际值时提供null或抛出异常。但它会破坏标准的流操作符,我只能将它用于我自己的操作符,这些操作符都知道这种行为。

澄清

评论中的人提议我takeWhile()运营商。这不是我的意思。如何更好地表达问题...我不是在问如何过滤(或限制)现有的流,我问如何动态创建(生成)流,而不是先加载所有元素,但是流会有有限的大小(事先未知)。

我正在寻找的代码是

    Iterator it = myCustomIteratorThatGeneratesTheSequence();
    StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);

我刚刚查看了java.nio.file.Fileslist(path)方法是如何实现的。

3 个答案:

答案 0 :(得分:16)

  

有没有合理的简单方法在Java中执行此操作,而不是自己实现整个Stream接口?

简单.limit()保证它将终止。但这并不总是足够强大。

Stream工厂方法之后,在不重新实现流处理管道的情况下创建海关流源的最简单方法是继承java.util.Spliterators.AbstractSpliterator<T>并将其传递给java.util.stream.StreamSupport.stream(Supplier<? extends Spliterator<T>>, int, boolean)

如果您打算使用并行流,请注意AbstractSpliterator仅产生次优分割。如果您可以更好地控制源代码,则可以更好地实现Spliterator接口。

  

例如,以下代码段将创建一个提供无限序列1,2,3 ...

的Stream

在该特定示例中,您可以使用IntStream.range()

  

但是流显然会在某个时刻完成,终端运营商喜欢(collect()或findAny())需要处理它。

findAny()这样的短路操作实际上可以在无限流上完成,只要有任何匹配的元素。

Java 9引入Stream.iterate为一些简单的情况生成有限流。

答案 1 :(得分:0)

科特林代码从InputStream创建JsonNode流


    private fun InputStream.toJsonNodeStream(): Stream<JsonNode> {
        return StreamSupport.stream(
                Spliterators.spliteratorUnknownSize(this.toJsonNodeIterator(), Spliterator.ORDERED),
                false
        )
    }

    private fun InputStream.toJsonNodeIterator(): Iterator<JsonNode> {
        val jsonParser = objectMapper.factory.createParser(this)

        return object: Iterator<JsonNode> {

            override fun hasNext(): Boolean {
                var token = jsonParser.nextToken()
                while (token != null) {
                    if (token == JsonToken.START_OBJECT) {
                        return true
                    }
                    token = jsonParser.nextToken()
                }
                return false
            }

            override fun next(): JsonNode {
                return jsonParser.readValueAsTree()
            }
        }
    }

答案 2 :(得分:0)

这是一个自定义且有限的流:

package org.tom.stream;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

public class GoldenStreams {
private static final String IDENTITY = "";

public static void main(String[] args) {
    Stream<String> stream = java.util.stream.StreamSupport.stream(new Spliterator<String>() {
        private static final int LIMIT = 25;
        private int integer = Integer.MAX_VALUE;
        {
            integer = 0;
        }
        @Override
        public int characteristics() {
            return Spliterator.DISTINCT;
        }
        @Override
        public long estimateSize() {
            return LIMIT-integer;
        }
        @Override
        public boolean tryAdvance(Consumer<? super String> arg0) {
            arg0.accept(IDENTITY+integer++);
            return integer < 25;
        }
        @Override
        public Spliterator<String> trySplit() {
            System.out.println("trySplit");
            return null;
        }}, false);
    List<String> peeks = new ArrayList<String>();
    List<String> reds = new ArrayList<String>();
    stream.peek(data->{
        peeks.add(data);
    }).filter(data-> {
        return Integer.parseInt(data)%2>0;
    }).peek(data ->{
        System.out.println("peekDeux:"+data);
    }).reduce(IDENTITY,(accumulation,input)->{
        reds.add(input);
        String concat = accumulation + ( accumulation.isEmpty() ? IDENTITY : ":") + input;
        System.out.println("reduce:"+concat);
        return concat;
    });
    System.out.println("Peeks:"+peeks.toString());
    System.out.println("Reduction:"+reds.toString());
}
}