如何创建无限流< 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< ;整数> 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
.