简介
其他答案展示了如何使用闭包来捕获函数的参数,无论其数量如何。这是一个很好的方法,并且非常有用,如果您提前知道参数,以便可以捕获它们。
这里我想展示另外两种不需要你事先知道参数的方法...
如果您以抽象的方式思考它,则不存在诸如具有多个参数的函数之类的东西。函数要么接收一组值(又名 tuple),要么接收一个参数并返回另一个接收另一个参数的函数,该函数又返回另一个返回...等等,序列的最后一个函数返回一个实际结果(又名 currying)。
不过,Java 中的方法可能有多个参数。因此,挑战在于构建始终接收单个参数(通过元组或柯里化)但实际上调用接收多个参数的方法的函数。
方法 #1:元组
所以第一种方法是使用 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,在调用时将参数现在传递给它:
SomeReturnType resultA = timedFunctionA.apply(Tuple2.of("a", "b"));
您可以对示例中的functionB 采取类似的方法,但您需要使用Tuple3<Integer, Integer, String[]> 作为参数(注意可变参数)。
这种方法的缺点是您需要创建许多Tuple 类,即Tuple2、Tuple3、Tuple4 等,因为Java 缺乏对元组的内置支持。
方法 #2:柯里化
另一种方法是使用一种称为currying 的技术,即接受一个参数的函数并返回另一个接受另一个参数的函数等,序列的最后一个函数返回实际结果。
以下是为您的 2 参数方法 functionA 创建 currified 函数的方法:
Function<String, Function<String, SomeReturnType>> currifiedFunctionA =
arg1 -> arg2 -> functionA(arg1, arg2);
按如下方式调用它:
SomeReturnType result = currifiedFunctionA.apply("a").apply("b");
如果您想装饰 currifiedFunctionA 使用上面定义的timerMethod 方法,您可以执行以下操作:
Function<String, Function<String, SomeReturnType>> timedCurrifiedFunctionA =
arg1 -> timerMethod("timerCurryA", arg2 -> functionA(arg1, arg2));
然后,调用 timedCurrifiedFunctionA,就像使用任何 currified 函数一样:
SomeReturnType result = timedCurrifiedFunctionA.apply("a").apply("b");
请注意,您只需要装饰序列的最后一个函数,即实际调用方法的函数,这是我们要测量的。
对于您的示例中的方法functionB,您可以采用类似的方法,只是currified 函数的类型现在是:
Function<Integer, Function<Integer, Function<String[], SomeResultType>>>
至少可以这么说,这很麻烦。所以这是 Java 中 currified 函数的缺点:表达它们类型的语法。另一方面,currified 函数使用起来非常方便,允许您应用多种函数式编程技术,而无需编写辅助类。