0

what is a best way of initializating a Stream with and object's method?

Foo foo1 = new Foo();
Foo foo2 = foo1.getNext();
Foo foo3 = foo2.getNext();

And I want a Stream of foo, foo1, foo2,... through the getNext() method.

I tried

Stream.iterate
Stream.generate

but these methods returns infinite streams.

  • .limit(.......) – snr Jul 12 '18 at 14:58
  • Size is unknown and all Foos cannot be retrieved eagerly, as it is very resource heavy method. – Vojta Šefler Jul 12 '18 at 15:04
  • can you use `Stream.of()` – Ash Jul 12 '18 at 15:09
  • 3
    How do you know when to stop? Note that streams are not eager, they will only produce elements as they are consumed. You might be interested in [Ending an “infinite” stream when certain conditions are met](https://stackoverflow.com/questions/49978246/ending-an-infinite-stream-when-certain-conditions-are-met). – Didier L Jul 12 '18 at 15:09
  • There is nothing wrong with `Stream.iterate(foo1, Foo::getNext)`. You didn’t tell under which condition it should stop. – Holger Jul 12 '18 at 16:08

2 Answers2

0

First idea that may come to mind would be to truncate the stream with limit:

Stream.iterate(foo1, Foo::getNext)
      .limit(size)....

but obviously, this is not useful if the size is unknown.

if the size is unknown then surely there must be some type of condition to say "stop and no more".

JDK-9 offers these overloads:

Stream.iterate(foo1, Foo::getNext)
      .takeWhile(f -> someCondition)
      ....  // further intermediate or a terminal operation

or:

Stream.iterate(foo1, f -> someCondition, Foo::getNext)
      .... // further intermediate or a terminal operation

if you cannot use JDK-9 then your only other option is to create your own helper method to perform the logic you're after.

Ousmane D.
  • 52,579
  • 8
  • 80
  • 117
0

It's not specified in the question, but I believe you want to stop iterating when getNext() returns null (it seems to make the most sense).

If so, there are at least three ways:

  1. If on JDK 9+, do what Aominè suggested:

    Stream.iterate(foo1, Objects::nonNull, Foo::getNext)
    
  2. If on JDK 8, and you don't mind introducing an extra dependency, use jOOλ and its iterateWhilePresent method:

    Seq.iterateWhilePresent(foo1, foo -> Optional.ofNullable(foo.getNext))
    
  3. If on JDK 8 and you don't want to introduce an extra dependency, write a method utilizing a custom Spliterator, for example (note that this is not the most efficient implementation as it calls generator eagerly):

    public static <T> Stream<T> iterateUntilNull(T seed, UnaryOperator<T> generator) {
        Spliterator<T> spliterator = new Spliterator<T>() {
            private T next = seed;
    
            @Override
            public boolean tryAdvance(Consumer<? super T> action) {
                if (next == null) {
                    return false;
                }
                action.accept(next);
                next = generator.apply(next);
                return true;
            }
    
            @Override
            public Spliterator<T> trySplit() {
                return null;
            }
    
            @Override
            public long estimateSize() {
                return Long.MAX_VALUE;
            }
    
            @Override
            public int characteristics() {
                return Spliterator.NONNULL;
            }
        };
        return StreamSupport.stream(spliterator, false);
    }
    

    and then call:

    iterateUntilNull(foo1, Foo::getNext)
    
Tomasz Linkowski
  • 4,186
  • 21
  • 38