Reducing a list of UnaryOperators in Java 8
functional-programming, java, java-8
Solution
The problem with using `compose` or `andThen` is that they're built into the `Function` interface and the type -- both compile-time and runtime types -- of the functions they return is `Function` and not `UnaryOperator` or a subinterface such as you've defined. For example, suppose we have
UnaryOperator<String> a = s -> s + "bar";
UnaryOperator<String> b = s -> s + s;
One might think we could write
UnaryOperator<String> c = a.compose(b);
but this doesn't work! Instead, one has to write
Function<String, String> c = a.compose(b);
For this to work, `UnaryOperator` would have to provide covariant overrides of `andThen` and `compose`. (Arguably this is a bug in the API.) You'd do the same in your subinterface. Or, it's simple enough to write out the lambdas by hand. For example,
interface MyOperator extends UnaryOperator<String> { }
public static void main(String[] args) {
List<MyOperator> list =
Arrays.asList(s -> s + "bar",
s -> "[" + s + "]",
s -> s + s);
MyOperator composite =
list.stream()
.reduce(s -> s, (a, b) -> s -> b.apply(a.apply(s)));
System.out.println(composite.apply("foo"));
}
This prints out `[foobar][foobar]`. Note that I've used the two-arg form of `reduce` in order to avoid having to deal with `Optional`.
Alternatively, if you're doing function composition a lot, you could reimplement the methods you need in your own interface. It's not too hard. These are based on the implementations in `java.util.Function` but with the concrete `String` type I've been using in this example substituted for the generics.
interface MyOperator extends UnaryOperator<String> {
static MyOperator identity() {
return s -> s;
}
default MyOperator andThen(MyOperator after) {
Objects.requireNonNull(after);
return s -> after.apply(this.apply(s));
}
default MyOperator compose(MyOperator before) {
Objects.requireNonNull(before);
return s -> this.apply(before.apply(s));
}
}
This would be used as follows:
MyOperator composite =
list.stream()
.reduce(MyOperator.identity(), (a, b) -> a.andThen(b));
Whether bulking up the interface in order to write `andThen` instead of a nested lambda is a matter of taste, I guess.
Problem
What is the preferred way of reducing a list of UnaryOperators in Java 8 till they represent one UnaryOperator that I can call apply on? For example I have the following ``` interface MyFilter extends UnaryOperator<MyObject>{}; public MyObject filterIt(List<MyFilter> filters,MyObject obj){ Optional<MyFilter> mf = filters .stream() .reduce( (f1,f2)->(MyFilter)f1.andThen(f2)); return mf.map(f->f.apply(obj)).orElse(obj); } ``` But this code throws a `ClassCastException` at `(MyFilter)f1.andThen(f2)`. I really want the effect of this code in the end: ``` MyObject o = obj; for(MyFilter f:filters){ o = f.apply(o); } return o; ``` But I am also curious of how we can reduce a collection of functions to one function, using `compose` or `andThen`.