java - 如何从 Iterator<E> 创建无限 Stream<E>?

标签 java iterator java-8 java-stream

看看我制作的以下类(class):

public class FibonacciSupplier implements Iterator<Integer> {
    private final IntPredicate hasNextPredicate;

    private int beforePrevious = 0;
    private int previous = 1;

    private FibonacciSupplier(final IntPredicate hasNextPredicate) {
        this.hasNextPredicate = hasNextPredicate;
    }

    @Override
    public boolean hasNext() {
        return hasNextPredicate.test(previous);
    }

    @Override
    public Integer next() {
        int result = beforePrevious + previous;
        beforePrevious = previous;
        previous = result;
        return result;
    }

    public static FibonacciSupplier infinite() {
        return new FibonacciSupplier(i -> true);
    }

    public static FibonacciSupplier finite(final IntPredicate predicate) {
        return new FibonacciSupplier(predicate);
    }
} 

以及它的用法:

public class Problem2 extends Problem<Integer> {
    @Override
    public void run() {
        result = toList(FibonacciSupplier.finite(i -> (i <= 4_000_000)))
                .stream()
                .filter(i -> (i % 2 == 0))
                .mapToInt(i -> i)
                .sum();
    }

    @Override
    public String getName() {
        return "Problem 2";
    }

    private static <E> List<E> toList(final Iterator<E> iterator) {
        List<E> list = new ArrayList<>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }
}

我怎样才能创建一个无限 Stream<E> ?

如果我使用 Stream<Integer> infiniteStream = toList(FibonacciSupplier.infinite()).stream() ,可能令人惊讶的是,我永远不会获得无限流。
相反,代码将在创建 list 时永远循环。在底层方法中。

到目前为止,这纯粹是理论上的,但如果我想先跳过无限流中的前 x 个数字,然后将其限制为最后 y 个数字,我绝对可以理解它的必要性,例如:

int x = MAGIC_NUMBER_X;
int y = MAGIC_NUMBER_y;
int sum = toList(FibonacciSupplier.infinite())
    .stream()
    .skip(x)
    .limit(y)
    .mapToInt(i -> i)
    .sum();

代码永远不会返回结果,应该怎么做?

最佳答案

您的错误是认为您需要一个Iterator 或一个Collection 来创建一个Stream。对于创建无限流,一个方法提供一个接一个的值就足够了。所以对于你的类 FibonacciSupplier 最简单的用法是:

IntStream s=IntStream.generate(FibonacciSupplier.infinite()::next);

或者,如果您更喜欢装箱的值:

Stream<Integer> s=Stream.generate(FibonacciSupplier.infinite()::next);

请注意,在这种情况下,方法不必命名为 next 也不必满足 Iterator 接口(interface)。但它是否与您的类(class)一样并不重要。此外,由于我们刚刚告诉流使用 next 方法作为 Supplier,因此永远不会调用 hasNext 方法。它只是无限的。

使用 Iterator 创建一个有限流有点复杂:

Stream<Integer> s=StreamSupport.stream(
  Spliterators.spliteratorUnknownSize(
    FibonacciSupplier.finite(intPredicate), Spliterator.ORDERED),
  false);

在这种情况下,如果您想要一个具有未装箱 int 值的有限 IntStream,您的 FibonacciSupplier 应该实现 PrimitiveIterator.OfInt.

关于java - 如何从 Iterator<E> 创建无限 Stream<E>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21956515/

相关文章:

java - "JAVA_HOME points to an invalid Java installation issue"在 Elasticsearch 中使用服务安装命令

java - 如何访问已上传到 NanoHTTPD 的文件?

java - 从txt中读取字符串到jsp中

java - 默认方法和静态方法如何在 Java 8 接口(interface)中工作?

java - 将一个对象拆分为对象列表 - 需要 JAVA8 解决方案

java - Thymeleaf 的 3 片段插入不起作用

java - 空指针异常 - Hadoop Mapreduce 作业

c++ - 谁应该拥有迭代器、我的数据类或该类中的实际列表?

C++模板类映射

java - 使用比较器对列表中的列表进行排序