我们说我有这个命令式代码:
List<Function<T, T>> functions = ...
T value = ...
for (Function<T, T> function : functions) {
value = function.apply(value);
}
如何在功能样式中编写它(如Scala中的折叠)?
答案 0 :(得分:12)
几个小时前刚刚问过Consumer
......您可以将它们缩减为单个函数并应用它:
@SafeVarargs
private static <T> Function<T, T> combineF(Function<T, T>... funcs) {
return Arrays.stream(funcs).reduce(Function.identity(), Function::andThen);
}
答案 1 :(得分:1)
以下是Eugene答案的变体,只是为了好玩:
public static <T> Function<T, T> combine(List<Function<T, T>> functions) {
return new Object() {
Function<List<Function<T, T>>, Function<T, T>> combiner = list ->
list.size() == 1 ? list.get(0) :
list.get(0).andThen(this.combiner.apply(list.subList(1, list.size())));
}.combiner.apply(functions);
}
这将创建一个匿名内部类,其属性是递归lambda。此属性名为combiner
,它是高阶函数,它将函数列表作为参数并返回函数作为结果。如果列表只包含一个元素,则此高阶函数返回列表的第一个函数,或者将andThen
应用于列表的第一个函数,其函数是递归调用高阶函数的结果使用以第二个元素开头的函数子列表。
需要匿名内部类,因为递归lambda只能被定义为类的属性。
毋庸置疑,这比使用Function::andThen
二元运算符流式传输列表更简单。此外,递归lambda不是免费的:它们使用堆栈进行递归调用。