JDK-8140283 : add Stream::transform method to facilitate fluent chaining of other methods
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util.stream
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2015-10-22
  • Updated: 2021-06-16
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
People like Optional and Stream because they allow chains of method calls. However, chaining only works for methods that are predefined. If an application wants to have a method or function that does something on a Stream (or Optional) and returns something that itself is chainable, the call to that method or function disrupts the nice linear chain.

For example, consider a method that transforms a stream by conditionally adding a filter stage:

    <T,U> Stream<U> maybeAddFilter(Stream<T> s) {
        if (condition)
            return s.filter(...);
        else
            return s;
    }

And suppose we have this pipeline:

    source.stream()
               .map(...)
               .collect(toList());

If we wanted to add the filter after the mapping operation, it would look like this:

    maybeAddFilter(
        source.stream()
                   .map(...))
        .collect(toList());

This disrupts the linear flow of the pipeline stages and makes the code confusing and hard to follow.

This could be mitigated by having a function called (for example) "chain" that takes a function to be chained, calls it passing "this", and returning its return value. On Stream<T>, this function would be declared something like this:

    <U> chain(Function<Stream<T>,U> func);

It would be used like so:

    source.stream()
               .map()
               .chain(this::maybeAddFilter)
               .collect(toList());

The chain method on Stream<T> wouldn't necessarily return another Stream; it could return anything.
Comments
Per discussion relating to JDK-8203442, consider "transform" for the name of this method.
04-12-2018

Another use-case for such chain() method may be to allow user to create custom implementations of Stream with their own collection of methods, which can be chained to standard Java stream producers. For example, if a user created HaskellStream with Haskell's stream methods, one could write: List.of(1, 2, 3, 4) .stream() .chain(HaskellStream::new) .drop() .indexed() ...
04-09-2018