看看下面的课程:
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();
代码不会返回结果,应该怎么做?
答案 0 :(得分:21)
您的错误是认为您需要Iterator
或Collection
才能创建Stream
。为了创建无限流,提供一个又一个值的单个方法就足够了。因此,对于您的班级FibonacciSupplier
,最简单的用法是:
IntStream s=IntStream.generate(FibonacciSupplier.infinite()::next);
或者,如果您更喜欢盒装值:
Stream<Integer> s=Stream.generate(FibonacciSupplier.infinite()::next);
请注意,在这种情况下,该方法不必命名为next
,也不必满足Iterator
接口。但是,如果它和你的班级一样,那也没关系。此外,由于我们刚刚告诉流使用next
方法作为Supplier
,因此永远不会调用hasNext
方法。这只是无限的。
使用Iterator
创建有限流有点复杂:
Stream<Integer> s=StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
FibonacciSupplier.finite(intPredicate), Spliterator.ORDERED),
false);
在这种情况下,如果您想要一个有限IntStream
个未加框的int
值,则FibonacciSupplier
应该实现PrimitiveIterator.OfInt
。
答案 1 :(得分:15)
在Java 8中,没有实现接口Stream的公共,具体类。但是,有一些静态工厂方法。其中最重要的是StreamSupport.stream。特别是,它被用于大多数集合类所包含的默认方法 Collection.stream中:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
此方法的默认实现通过调用spliterator()
创建Spliterator,并将创建的对象传递给工厂方法。 Spliterator 是Java 8引入的新接口,用于支持并行流。它与 Iterator 类似,但与后者相反, Spliterator 可以分为多个部分,可以单独处理。有关详细信息,请参阅Spliterator.trySplit。
默认方法 Iterable.spliterator也在Java 8中添加,因此每个 Iterable 类都会自动支持 Spliterators 。实现如下:
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
该方法从任意 Iterator 创建 Spliterator 。如果您将这两个步骤结合起来,则可以从任意 Iterator 创建 Stream :
<T> Stream<T> stream(Iterator<T> iterator) {
Spliterator<T> spliterator
= Spliterators.spliteratorUnknownSize(iterator, 0);
return StreamSupport.stream(spliterator, false);
}
要获得 Spliterators 的印象,这是一个非常简单的示例,不使用集合。以下类实现 Spliterator 以迭代半开的整数间隔:
public final class IntRange implements Spliterator.OfInt {
private int first, last;
public IntRange(int first, int last) {
this.first = first;
this.last = last;
}
public boolean tryAdvance(IntConsumer action) {
if (first < last) {
action.accept(first++);
return true;
} else {
return false;
}
}
public OfInt trySplit() {
int size = last - first;
if (size >= 10) {
int temp = first;
first += size / 2;
return new IntRange(temp, first);
} else {
return null;
}
}
public long estimateSize() {
return Math.max(last - first, 0);
}
public int characteristics() {
return ORDERED | DISTINCT | SIZED | NONNULL
| IMMUTABLE | CONCURRENT | SUBSIZED;
}
}
答案 2 :(得分:0)
要添加另一个答案,也许AbstractSpliterator是更好的选择,特别是在示例代码的情况下。生成是不灵活的,因为除了使用限制之外没有[好]方式给出停止条件。限制只接受许多项目而不是谓词,所以我们必须知道我们想要生成多少项目 - 这可能是不可能的,如果生成器是传递给我们的黑盒子怎么办?
AbstractSpliterator是必须编写整个分裂器和使用Iterator / Iterable之间的中途。 AbstractSpliterator只缺少tryAdvance方法,我们首先检查谓词是否完成,如果没有将生成的值传递给动作。这是使用AbstractIntSpliterator的Fibonacci序列的一个例子:
public class Fibonacci {
private static class FibonacciGenerator extends Spliterators.AbstractIntSpliterator
{
private IntPredicate hasNextPredicate;
private int beforePrevious = 0;
private int previous = 0;
protected FibonacciGenerator(IntPredicate hasNextPredicate)
{
super(Long.MAX_VALUE, 0);
this.hasNextPredicate = hasNextPredicate;
}
@Override
public boolean tryAdvance(IntConsumer action)
{
if (action == null)
{
throw new NullPointerException();
}
int next = Math.max(1, beforePrevious + previous);
beforePrevious = previous;
previous = next;
if (!hasNextPredicate.test(next))
{
return false;
}
action.accept(next);
return true;
}
@Override
public boolean tryAdvance(Consumer<? super Integer> action)
{
if (action == null)
{
throw new NullPointerException();
}
int next = Math.max(1, beforePrevious + previous);
beforePrevious = previous;
previous = next;
if (!hasNextPredicate.test(next))
{
return false;
}
action.accept(next);
return true;
}
}
public static void main(String args[])
{
Stream<Integer> infiniteStream = StreamSupport.stream(
new FibonacciGenerator(i -> true), false);
Stream<Integer> finiteStream = StreamSupport.stream(
new FibonacciGenerator(i -> i < 100), false);
// Print with a side-effect for the demo
infiniteStream.limit(10).forEach(System.out::println);
finiteStream.forEach(System.out::println);
}
}
有关详细信息,我在我的博客http://thecannycoder.wordpress.com/
中介绍了Java 8中的生成器答案 3 :(得分:0)
您可以使用低级流支持原语和Spliterators
库从Iterator
生成流。
StreamSupport.stream()
的最后一个参数表示流不是并行的。一定要这样,因为你的Fibonacci迭代器依赖于之前的迭代。
return StreamSupport.stream( Spliterators.spliteratorUnknownSize( new Iterator<Node>()
{
@Override
public boolean hasNext()
{
// to implement
return ...;
}
@Override
public ContentVersion next()
{
// to implement
return ...;
}
}, Spliterator.ORDERED ), false );