-
Enhancement
-
Resolution: Unresolved
-
P4
-
None
-
None
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.
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.
- duplicates
-
JDK-8210372 Streams should allow chaining with custom stream implementations
- Closed
-
JDK-8213112 Add the 'process' method to Stream class
- Closed
- relates to
-
JDK-8203442 String::transform
- Resolved