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.

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.
  • 54,915
  • 8
  • 91
  • 126
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,386
  • 23
  • 38