如何创建无限流< E>超出迭代器< E>?

如何创建无限流< E>超出迭代器< E>?

问题描述:

查看以下课程:

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

我如何创建无限 流< E>

如果我使用 Stream&lt ;整数&GT; infiniteStream = toList(FibonacciSupplier.infinite())。stream(),我可能会惊讶地发现,永远不会得到无限的流。

相反,代码会永远循环创建基础方法中的列表

If I were to use Stream<Integer> infiniteStream = toList(FibonacciSupplier.infinite()).stream(), I would, possibly surprisingly, never get an infinite stream.
Instead the code would loop forever in the creation of the list in an underlying method.

到目前为止,这纯粹是理论上的,但我可以肯定地了解需要因为如果我想首先从无限流中跳过前x个数字,然后用最后的y数限制它,例如:

This so far is purely theoretical, but I can definately understand the need for it if I would want to first skip the first x numbers from an infinite stream, and then limit it by the last y numbers, something like:

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

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

The code would not ever return a result, how should it be done?

你的错误是认为你需要 Iterator 收集以创建。为了创建无限流,提供一个又一个值的单个方法就足够了。所以对于你的班级 FibonacciSupplier 最简单的用法是:

Your mistake is to think that you need an Iterator or a Collection to create a Stream. For creating an infinite stream, a single method providing one value after another is enough. So for your class FibonacciSupplier the simplest use is:

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

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

or, if you prefer boxed values:

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

请注意,在这种情况下,该方法不必命名为 next 也不满足 Iterator 界面。但是,如果它和你的班级一样没关系。此外,正如我们刚刚告诉流使用 next 方法作为供应商将永远不会调用hasNext 方法。它只是无限的。

Note that in this case the method does not have to be named next nor fulfill the Iterator interface. But it doesn’t matter if it does as with your class. Further, as we just told the stream to use the next method as a Supplier, the hasNext method will never be called. It’s just infinite.

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

Creating a finite stream using your Iterator is a bit more complicated:

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

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

In this case if you want a finite IntStream with unboxed int values your FibonacciSupplier should implement PrimitiveIterator.OfInt.