Proposal: Stream.iterateWhile(T seed, Function<T, Optional<T>> mapper)

Tomasz Linkowski t.linkowski at
Fri Oct 26 15:44:36 UTC 2018


Please, consider adding a new static method to the `Stream` interface
(names TBD):

        static <T> Stream<T> iterateWhile(
            T seed, Function<? super T, ? extends Optional<? extends T>>


+ non-null equivalent of `Stream.iterate(seed, hasNext, next)` [1]
+ `mapper` like in `Optional.flatMap(mapper)` [2]
+ shift from two operations to one operation, like in:
    - `Iterator.hasNext/next` => `Spliterator.tryAdvance`
    - pattern matching (test/bind)
+ intent: "nudge towards writing clearer code" (Brian Goetz about LVTI [3])
+ useful for `Optional`-based APIs
+ trivial implementation


`Stream.iterate(seed, hasNext, next)` is great for nullable-return-based
APIs. Example: returning a chain of `Throwable` causes:

        Stream.iterate(throwable, Objects::nonNull, Throwable::getCause)

For `Optional`-based APIs, using `Stream.iterate` becomes cumbersome.
Example (assume `Throwable.findCause()` returns `Optional`):

        Stream.iterate(throwable, Objects::nonNull, t ->

Using the proposed method, the above can become much clearer:

        Stream.iterateWhile(throwable, Throwable::findCause)

This is just one example - I can provide more if needed.


Preferred implementation:

        iterateWhile(seed, mapper) -> Stream.iterate(
            seed, Objects::nonNull,
            t ->  mapper.apply(t).orElse(null)

Equivalent `Optional`-based implementation:

        iterateWhile(seed, mapper) -> Stream.iterate(
                Optional.ofNullable(seed), Optional::isPresent,
                optional ->  optional.flatMap(mapper)

Note that both implementations assume that `null` seed yields an empty

== NAMING ==

Name `iterate` cannot be safely overloaded because of
`Stream.iterate(UnaryOperator)` so another name needs to be used. I
proposed `iterateWhile` inspired by `takeWhile` but maybe it's a wrong
trail (`takeWhile` takes a `Predicate`). Other names that come to my mind:
`iterateWhilePresent`, `iterateOptional`, `iterateNonNull`.


Tomasz Linkowski

More information about the core-libs-dev mailing list