Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
164 views
in Technique[技术] by (71.8m points)

java - How to create an infinite Stream<E> out of an Iterator<E>?

Looking at the following class I've made:

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

And the usage of it in:

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

How would I be able to create an infinite Stream<E>?

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.

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

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.

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

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...