使用stream编写函数数组

时间:2017-12-11 14:47:21

标签: java function java-8 java-stream

我想为一个函数组合一个函数数组。给定多个函数,该方法应返回一个函数,该函数是输入函数的组合。

一种方法是

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;
}

我希望首先制作一系列函数来实现相同的结果。但我无法弄清楚如何做到这一点

public static <T> Function<T,T> composeAll2 (Function<T,T>... functions){
    Function<T,T> res = Function.identity();
    Arrays.stream(functions). ??? 
    return res;
}

我现在应该在最后一个提出问号的方法中输入什么代码?

2 个答案:

答案 0 :(得分:6)

您可以使用Stream#reduce()操作:

public static <T> Function<T,T> composeAll2 (Function<T,T>... functions){
    return Arrays.stream(functions).reduce(Function.identity(), Function::compose);
}

这与您组成函数的迭代方式完全相同。

答案 1 :(得分:4)

虽然@ Lino的答案很简洁,但它不安全且容易出现堆栈溢出:

List<Function<Integer, Integer>> list = Collections.nCopies(10000, i -> i + 1);
System.out.println(composeAll2(list.toArray(new Function[0])).apply(0));

如果运行此代码,它将因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)
    ...

为了避免这种情况,我建议不要使用流并使用旧的for-each循环:

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;
    };
}

此版本的composeAll2将使用常量堆栈空间。