如何从Iterator <E>中创建一个无限的Stream <E>?

ski*_*iwi 22 java iterator java-8 java-stream

看看下面的课程我做了:

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);
    }
} 
Run Code Online (Sandbox Code Playgroud)

它的用法在:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我怎么能创造一个无限的 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();
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 23

你的错误是认为你需要一个Iterator或一个Collection创建一个Stream.为了创建无限流,提供一个又一个值的单个方法就足够了.因此,对于您的班级FibonacciSupplier,最简单的用途是:

IntStream s=IntStream.generate(FibonacciSupplier.infinite()::next);
Run Code Online (Sandbox Code Playgroud)

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

Stream<Integer> s=Stream.generate(FibonacciSupplier.infinite()::next);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


nos*_*sid 16

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

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}
Run Code Online (Sandbox Code Playgroud)

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

默认方法 Iterable.spliterator也被加入在Java中8,让每一个可迭代类自动支持Spliterators.实现如下:

default Spliterator<T> spliterator() {
    return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
Run Code Online (Sandbox Code Playgroud)

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

<T> Stream<T> stream(Iterator<T> iterator) {
    Spliterator<T> spliterator
        = Spliterators.spliteratorUnknownSize(iterator, 0);
    return StreamSupport.stream(spliterator, false);
}
Run Code Online (Sandbox Code Playgroud)

为了获得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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你能解释一下它究竟做了什么吗?我理解几乎所有Java 8的概念,但是"Spliterator"仍然很难掌握. (2认同)