如何从Iterator 中创建无限的Stream ?

看看下面我上面写的课:

public class FibonacciSupplier implements Iterator { 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 { @Override public void run() { result = toList(FibonacciSupplier.finite(i -> (i  (i % 2 == 0)) .mapToInt(i -> i) .sum(); } @Override public String getName() { return "Problem 2"; } private static  List toList(final Iterator iterator) { List list = new ArrayList(); while (iterator.hasNext()) { list.add(iterator.next()); } return list; } } 

我怎样才能创建无限的 Stream

如果我使用Stream 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 s=Stream.generate(FibonacciSupplier.infinite()::next); 

请注意,在这种情况下,该方法不必next命名,也不必满足Iterator接口。 但是,如果它和你的class级一样没关系。 此外,由于我们刚刚告诉流使用next方法作为Supplier ,因此永远不会hasNext方法。 这只是无限的。

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

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

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

在Java 8中,没有实现接口Stream的 公共,具体类 。 但是,有一些静态工厂方法 。 其中最重要的是StreamSupport.stream 。 特别是,它在默认方法 Collection.stream中使用 – 由大多数集合类inheritance:

 default Stream stream() { return StreamSupport.stream(spliterator(), false); } 

此方法的默认实现通过调用spliterator()创建Spliterator ,并将创建的对象传递给factory方法。 Spliterator是Java 8引入的新接口,用于支持并行流 。 它与Iterator类似,但与后者相反, Spliterator可以分为多个部分,可以单独处理。 有关详细信息,请参阅Spliterator.trySplit 。

在Java 8中也添加了默认方法 Iterable.spliterator ,因此每个Iterable类都自动支持Spliterators 。 实现如下:

 default Spliterator spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } 

该方法从任意迭代器创建Spliterator 。 如果将这两个步骤组合在一起,则可以从任意迭代器创建一个Stream

  Stream stream(Iterator iterator) { Spliterator 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; } } 

要添加另一个答案,也许AbstractSpliterator是更好的选择,特别是在示例代码的情况下。 生成是不灵活的,因为除了使用限制之外没有[好]方式给出停止条件。 限制只接受许多项而不是谓词,所以我们必须知道我们想要生成多少项 – 这可能是不可能的,如果生成器是传递给我们的黑盒子怎么办?

AbstractSpliterator是必须编写整个spliterator和使用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 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 infiniteStream = StreamSupport.stream( new FibonacciGenerator(i -> true), false); Stream 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中的生成器。

您可以使用低级流支持原语和Spliterators库从Iterator创建流。

StreamSupport.stream()的最后一个参数表示流不是并行的。 一定要这样,因为你的Fibonacci迭代器取决于之前的迭代。

 return StreamSupport.stream( Spliterators.spliteratorUnknownSize( new Iterator() { @Override public boolean hasNext() { // to implement return ...; } @Override public ContentVersion next() { // to implement return ...; } }, Spliterator.ORDERED ), false );