I want to compose an array of functions to one function. Given multiple functions the method should return a function which is the composition of the input functions.
One way to do this is
public static <T> Function<T,T> composeAll(Function<T,T>... functions){
    Function<T,T> res = Function.identity();
    for(Function<T,T> f : functions){
       res = res.compose(f);
    }
    return res;
}
I'm looking to achieve the same result by first making a stream of the array of functions. But I can't figure out how to do this
public static <T> Function<T,T> composeAll2 (Function<T,T>... functions){
    Function<T,T> res = Function.identity();
    Arrays.stream(functions). ??? 
    return res;
}
What code should I enter in the last method where I put question marks now?
You can make use of the Stream#reduce() operation:
public static <T> Function<T,T> composeAll2 (Function<T,T>... functions){
    return Arrays.stream(functions).reduce(Function.identity(), Function::compose);
}
Which is identical to your iterative way of composing functions.
While @Lino's answer is concise, it is unsafe and prone to stack overflow:
List<Function<Integer, Integer>> list = Collections.nCopies(10000, i -> i + 1);
System.out.println(composeAll2(list.toArray(new Function[0])).apply(0));
If you run this code, it will fail with StackOverflowError:
Exception in thread "main" java.lang.StackOverflowError
    at java.util.function.Function.lambda$compose$0(Function.java:68)
    at java.util.function.Function.lambda$compose$0(Function.java:68)
    at java.util.function.Function.lambda$compose$0(Function.java:68)
    at java.util.function.Function.lambda$compose$0(Function.java:68)
    at java.util.function.Function.lambda$compose$0(Function.java:68)
    at java.util.function.Function.lambda$compose$0(Function.java:68)
    ...
To avoid this, I suggest not using streams at all and using the old for-each loop:
public static <T> Function<T,T> composeAll2(Function<T,T>... functions){
    return input -> {
        T res = input;
        for (Function<T, T> f : functions) {
            res = f.apply(res);
        }
        return res;
    };
}
This version of composeAll2 will use a constant stack space.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With