我有一个关于Java 8函数式编程的问题。我正在尝试使用函数式编程来实现一些目标,并需要一些关于如何实现它的指导。
我的要求是在计时器函数中包装每一个方法执行,这是方法执行的时间。这里是计时器函数和我需要计时的两个函数的例子。
timerMethod(String timerName, Function func){
timer.start(timerName)
func.apply()
timer.stop()
}
functionA(String arg1, String arg2)
functionB(int arg1, intArg2, String ...arg3)我试图将functionA & functionB传递给timerMethod,但是functionA & functionB需要不同数量和类型的参数来执行。
任何想法我都能实现。
谢谢!!
发布于 2017-07-14 14:54:48
不要抓住这些论点,然后在最后一刻把它们传递出去。立即传递它们,但是通过用另一个函数包装函数来延迟调用它:
Producer<?> f1 =
() -> functionA(arg1, arg2);
Producer<?> f2 =
() -> functionB(arg1, arg2, arg3);在这里,我将每个函数调用包装在一个lambda (() ->...)中,其中包含了0个参数。然后,稍后再打电话给他们,不带任何参数:
f1()
f2()这对您在lambda中提供的参数形成了一个闭包,这允许您稍后使用变量,尽管通常情况下,这些变量是GC为超出作用域而提供的。
注意,我有一个?作为Producer的类型,因为我不知道函数返回什么类型。将?更改为每个函数的返回类型。
发布于 2017-07-14 14:56:57
您应该通过分离关注点将其分为两件事,以使代码易于使用和维护。一个是定时,另一个是调用的,例如:
// v--- invoking occurs in request-time
R1 result1 = timerMethod("functionA", () -> functionA("foo", "bar"));
R2 result2 = timerMethod("functionB", () -> functionB(1, 2, "foo", "bar"));
// the timerMethod only calculate the timing-cost
<T> T timerMethod(String timerName, Supplier<T> func) {
timer.start(timerName);
try {
return func.get();
} finally {
timer.stop();
}
}如果希望返回函数接口而不是该方法的结果,可以按以下方式完成:
Supplier<R1> timingFunctionA =timerMethod("A", ()-> functionA("foo", "bar"));
Supplier<R2> timingFunctionB =timerMethod("B", ()-> functionB(1, 2, "foo", "bar"));
<T> Supplier<T> timerMethod(String timerName, Supplier<T> func) {
// v--- calculate the timing-cost when the wrapper function is invoked
return () -> {
timer.start(timerName);
try {
return func.get();
} finally {
timer.stop();
}
};
}备注
如果所有函数的返回类型都是void,则可以用Runnable替换Supplier,然后将timerMethod的返回类型改为void &从timerMethod删除return关键字。
如果您的一些函数会抛出一个检查异常,您可以用Callable & invoke Callable#call代替Supplier。
发布于 2017-07-16 02:38:57
引言
其他答案显示了如何使用闭包来捕获函数的参数,而不管其数量如何。这是一种很好的方法,如果您事先知道参数(),那么它非常有用,这样就可以捕获它们。
在这里,我想展示另外两种方法,它们不需要你事先知道这些论点.
如果你以抽象的方式思考它,就不会有多个参数的函数这样的东西。函数要么接收一组值(又称元组),要么接收单个参数,然后返回另一个接收另一个参数的函数,而另一个参数函数则返回返回.等,用序列的最后一个函数返回一个实际的结果(也称为赛跑)。
不过,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"));现在,为了用您的functionA方法来装饰timerMethod,您需要做一些修改:
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块来使代码更加健壮,如霍利-爪哇的回答所示。
下面是如何将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[]> (处理varargs参数)。
这种方法的缺点是需要创建许多Tuple类,如Tuple2、Tuple3、Tuple4等,因为Java缺乏对元组的内置支持。
方法2:赛跑
另一种方法是使用一种名为https://en.wikipedia.org/wiki/Currying的技术,即接受一个参数的函数,返回另一个接受另一个参数的函数,等等,序列的最后一个函数返回实际结果。
下面是如何为您的2参数方法functionA创建一个简化的函数
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,就像调用任何配置好的函数一样:
SomeReturnType result = timedCurrifiedFunctionA.apply("a").apply("b");请注意,您只需要修饰序列的最后一个函数,即对方法进行实际调用的函数,这就是我们要度量的。
对于示例中的方法functionB,可以采取类似的方法,只不过现在currified函数的类型是:
Function<Integer, Function<Integer, Function<String[], SomeResultType>>>至少可以说,这很麻烦。因此,这是Java中受限制的函数的缺点:用来表示其类型的语法。另一方面,使用简约函数非常方便,并允许您应用几种函数式编程技术,而不需要编写助手类。
https://stackoverflow.com/questions/45105875
复制相似问题