介绍
其他答案展示了如何使用闭包来捕获函数的参数,无论其数量。这是一种很好的方法,非常有用,如果您事先知道参数,以便可以捕获它们。
在这里,我想展示另外两种方法,不需要您事先知道参数...
如果您从抽象的角度考虑,不存在具有多个参数的函数。函数要么接收一个值集合(也称为元组),要么接收一个单一参数并返回另一个接收另一个单一参数的函数,然后返回另一个一参数函数,以此类推,序列的最后一个函数返回实际结果(也称为柯里化)。
Java中的方法可能具有多个参数。因此,挑战在于构建始终只接收一个参数的函数(通过元组或柯里化),但实际上调用接收多个参数的方法。
方法一:元组
第一种方法是使用 Tuple
辅助类,并使您的函数接收一个元组,可以是 Tuple2
或 Tuple3
:
因此,您示例中的 functionA
可能会接收 一个单独的 Tuple2<String, String>
作为参数:
Function<Tuple2<String, String>, SomeReturnType> functionA = tuple ->
functionA(tuple.getFirst(), tuple.getSecond());
你可以按如下方式调用它:
SomeReturnType resultA = functionA.apply(Tuple2.of("a", "b"));
现在,为了使用你的
timerMethod
方法装饰
functionA
函数,你需要进行一些修改:
static <T, R> Function<T, R> timerMethod(
String timerName,
Function<? super T, ? extends R> func){
return t -> {
timer.start(timerName);
R result = func.apply(t);
timer.stop();
return result;
};
}
请注意,您应该使用
try/finally
块使您的代码更加健壮,如
holi-java's answer所示。
以下是您可能如何使用
timerMethod
方法来执行
functionA
:
Function<Tuple2<String, String>, SomeReturnType> timedFunctionA = timerMethod(
"timerA",
tuple -> functionA(tuple.getFirst(), tuple.getSecond());
您可以像调用其他函数一样调用timedFunctionA
,在调用时传递参数now:
SomeReturnType resultA = timedFunctionA.apply(Tuple2.of("a", "b"));
您可以采用类似的方法来处理示例中的
functionB
,只是需要使用
Tuple3<Integer, Integer, String[]>
作为参数(处理可变参数)。
这种方法的缺点是需要创建许多Tuple
类,例如Tuple2
、Tuple3
、Tuple4
等,因为Java缺乏对元组的内置支持。
方法二:柯里化
另一种方法是使用一种称为柯里化的技术,即接受一个单一参数并返回另一个接受另一个单一参数的函数,以此类推,序列中的最后一个函数返回实际结果。
以下是如何为您的双参数方法functionA
创建柯里化函数:
Function<String, Function<String, SomeReturnType>> currifiedFunctionA =
arg1 -> arg2 -> functionA(arg1, arg2);
按以下方式调用:
SomeReturnType result = currifiedFunctionA.apply("a").apply("b");
如果你想使用上面定义的
timerMethod
方法装饰
currifiedFunctionA
,可以按照以下步骤进行:
Function<String, Function<String, SomeReturnType>> timedCurrifiedFunctionA =
arg1 -> timerMethod("timerCurryA", arg2 -> functionA(arg1, arg2));
然后,正如对任何柯里化函数一样,调用timedCurrifiedFunctionA
:
SomeReturnType result = timedCurrifiedFunctionA.apply("a").apply("b");
请注意,您只需要装饰序列的最后一个函数,即实际调用方法的函数,这是我们想要测量的内容。
对于您示例中的
functionB
方法,您可以采用类似的方法,但现在柯里化函数的类型将是:
Function<Integer, Function<Integer, Function<String[], SomeResultType>>>
可以说,Java中柯里化函数的缺点在于其类型表达式语法相当繁琐。但另一方面,柯里化函数非常实用,可以应用多种函数式编程技术而无需编写辅助类。