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`.

Original source