xtr*_*tra 3 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;
}
Run Code Online (Sandbox Code Playgroud)
我希望通过首先创建函数数组的流来实现相同的结果.但我无法弄清楚如何做到这一点
public static <T> Function<T,T> composeAll2 (Function<T,T>... functions){
Function<T,T> res = Function.identity();
Arrays.stream(functions). ???
return res;
}
Run Code Online (Sandbox Code Playgroud)
我现在应该在最后一个提出问号的方法中输入什么代码?
您可以使用该Stream#reduce()
操作:
public static <T> Function<T,T> composeAll2 (Function<T,T>... functions){
return Arrays.stream(functions).reduce(Function.identity(), Function::compose);
}
Run Code Online (Sandbox Code Playgroud)
这与您组成函数的迭代方式完全相同.
虽然@Lino 的回答很简洁,但它不安全且容易发生堆栈溢出:
List<Function<Integer, Integer>> list = Collections.nCopies(10000, i -> i + 1);
System.out.println(composeAll2(list.toArray(new Function[0])).apply(0));
Run Code Online (Sandbox Code Playgroud)
如果您运行此代码,它将失败并显示 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)
...
Run Code Online (Sandbox Code Playgroud)
为了避免这种情况,我建议根本不使用流并使用旧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;
};
}
Run Code Online (Sandbox Code Playgroud)
这个版本composeAll2
将使用一个恒定的堆栈空间。