Functional programming Java8函数式编程-传递函数及其参数

Functional programming Java8函数式编程-传递函数及其参数,functional-programming,java-8,Functional Programming,Java 8,我有一个关于Java8函数式编程的问题。我正在尝试使用函数式编程实现一些东西,需要一些关于如何实现的指导 我的要求是将每个方法执行封装在计时器函数中,计时器函数对方法执行进行计时。下面是计时器函数的示例,以及我需要计时的两个函数 timerMethod(String timerName, Function func){ timer.start(timerName) func.apply() timer.stop() } functionA(String arg1, String a

我有一个关于Java8函数式编程的问题。我正在尝试使用函数式编程实现一些东西,需要一些关于如何实现的指导

我的要求是将每个方法执行封装在计时器函数中,计时器函数对方法执行进行计时。下面是计时器函数的示例,以及我需要计时的两个函数

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
需要不同数量和类型的参数来执行

我有什么想法可以实现它吗


谢谢

不要保留论点,然后在最后一刻传递它们。立即传递它们,但通过使用另一个函数包装函数来延迟调用该函数:

Producer<?> f1 =
    () -> functionA(arg1, arg2);

Producer<?> f2 =
    () -> functionB(arg1, arg2, arg3);
SomeReturnType result = timedCurrifiedFunctionA.apply("a").apply("b");
这将对lambda中提供的参数形成一个闭包,这允许您稍后使用变量,即使通常情况下它们会因超出范围而被GC


注意,我有一个
作为
生产者的类型,因为我不知道您的函数返回什么类型。将
更改为每个函数的返回类型

为了使代码易于使用和维护,您应该将其分为两部分。一个是定时,另一个是调用,例如:

//                                       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();
    }
}
//v---调用在请求时发生
R1 result1=timerMethod(“functionA”,()->functionA(“foo”,“bar”);
R2结果2=时间方法(“函数B”,()->函数B(1,2,“foo”,“bar”);
//timerMethod只计算计时成本
T timerMethod(字符串timerName,供应商函数){
timer.start(timerName);
试一试{
返回函数get();
}最后{
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();
        }
    };
}
Supplier timingFunctionA=timerMethod(“A”),()->functionA(“foo”,“bar”);
供应商计时功能B=计时方法(“B”),()->功能B(1,2,“foo”,“bar”);
供应商timerMethod(字符串timerName,供应商函数){
//v---计算调用包装器函数时的时间开销
返回()->{
timer.start(timerName);
试一试{
返回函数get();
}最后{
timer.stop();
}
};
}
笔记 如果所有函数的返回类型都是
void
,您可以将
供应商
替换为
Runnable
,然后将
timerMethod
的返回类型设置为
void
&从
timerMethod
中删除
返回
关键字

如果您的某些函数将抛出选中的异常,您可以用
可调用
替换
供应商
&调用
可调用#调用

导言 其他答案显示了如何使用闭包来捕获函数的参数,无论其数量如何。这是一种很好的方法,非常有用,如果您事先知道参数,那么就可以捕获它们

在这里,我想展示另外两种方法,它们不需要你事先知道论点

如果你从抽象的角度来考虑,就不存在有多个参数的函数。函数要么接收一组值(也称为元组),要么接收一个单参数并返回另一个接收另一个单参数的函数,该函数反过来返回另一个单参数函数,该函数返回。。。等,序列的最后一个函数返回实际结果(也称为currying)

但是,Java中的方法可能有多个参数。因此,挑战在于构建总是接收一个参数的函数(通过元组或curry),但实际上调用接收多个参数的方法


方法1:元组 因此,第一种方法是使用helper类,让函数接收一个元组,要么是
Tuple2
,要么是
Tuple3

因此,示例中的
函数可能会收到一个
Tuple2
作为参数:

Function<Tuple2<String, String>, SomeReturnType> functionA = tuple -> 
    functionA(tuple.getFirst(), tuple.getSecond());
现在,为了用
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;
    };
}
您可以像调用任何其他函数一样调用
timedFunctionA
,在调用时立即将参数传递给它:

SomeReturnType resultA = timedFunctionA.apply(Tuple2.of("a", "b"));
您可以对示例中的
函数b
采取类似的方法,只是需要对参数使用
Tuple3
(注意varargs参数)

这种方法的缺点是需要创建许多
Tuple
类,即
Tuple2
Tuple3
Tuple4
,等等,因为Java缺乏对元组的内置支持


方法2:咖喱 另一种方法是使用一种称为的技术,即接受一个单参数的函数和返回另一个接受另一个单参数的函数等,序列的最后一个函数返回实际结果

下面是如何为双参数方法
function
创建一个currified函数:

Function<Tuple2<String, String>, SomeReturnType> timedFunctionA = timerMethod(
    "timerA", 
    tuple -> functionA(tuple.getFirst(), tuple.getSecond());
Function<String, Function<String, SomeReturnType>> currifiedFunctionA =
    arg1 -> arg2 -> functionA(arg1, arg2);
如果要使用上面定义的
timerMethod
方法装饰
currifiedfunction
,可以执行以下操作:

SomeReturnType resultA = functionA.apply(Tuple2.of("a", "b"));
SomeReturnType result = currifiedFunctionA.apply("a").apply("b");
Function<String, Function<String, SomeReturnType>> timedCurrifiedFunctionA =
    arg1 -> timerMethod("timerCurryA", arg2 -> functionA(arg1, arg2));
请注意,您只需要修饰序列的最后一个函数,即对方法进行实际调用的函数,这是我们想要度量的

对于示例中的方法
functionB
,您可以采用类似的方法,不同的是,currified函数的类型现在是:

Function<Integer, Function<Integer, Function<String[], SomeResultType>>>
函数
至少可以说,这相当麻烦。因此,这就是Java中curried函数的缺点:表示其类型的语法。在…上
Function<Integer, Function<Integer, Function<String[], SomeResultType>>>