我有一个方法,大约有十行代码。我想创建更多的方法来做完全相同的事情,除了一个会改变一行代码的小计算。这是一个传递函数指针来替换这一行的完美应用程序,但是Java没有函数指针。我最好的选择是什么?


当前回答

开源安全镜像项目将上面提到的一些解决方案泛化到一个向Java添加函数、委托和事件的库中。

有关特性的小抄,请参阅README或此stackoverflow答案。

至于函数,标准库引入了一个Fun接口和一些子接口(与泛型一起),它们组成了一个流畅的API,用于将方法用作类型。

Fun.With0Params<String> myFunctionField = "   hello world   "::trim;`  
Fun.With2Params<Boolean, Object, Object> equals = Objects::equals;`  
    
public void foo(Fun.With1ParamAndVoid<String> printer) throws Exception {
    printer.invoke("hello world);
}  

public void test(){
    foo(System.out::println);
}  

注意:

必须选择与目标签名中的参数数量相匹配的子接口。Fx,如果它有一个参数,选择Fun.With1Param。 泛型用于定义A)返回类型和B)签名的参数。

另外,请注意传递给foo()方法调用的方法引用的签名必须与方法foo定义的Fun匹配。如果不这样做,编译器将发出一个错误。

其他回答

看看lambdaj

http://code.google.com/p/lambdaj/

特别是它新的闭包特征

http://code.google.com/p/lambdaj/wiki/Closures

你会发现一种非常易读的方式来定义闭包或函数指针,而无需创建无意义的接口或使用丑陋的内部类

好吧,这个帖子已经足够老了,所以我的回答很可能对这个问题没有帮助。但是因为这个帖子帮助我找到了我的解决方案,我还是把它放在这里。

我需要使用一个具有已知输入和已知输出(都是double)的变量静态方法。因此,知道了方法包和名称后,我可以这样工作:

java.lang.reflect.Method Function = Class.forName(String classPath).getMethod(String method, Class[] params);

对于接受一个double作为参数的函数。

在具体情况下,我用

java.lang.reflect.Method Function = Class.forName("be.qan.NN.ActivationFunctions").getMethod("sigmoid", double.class);

并在以后更复杂的情况下调用它

return (java.lang.Double)this.Function.invoke(null, args);

java.lang.Object[] args = new java.lang.Object[] {activity};
someOtherFunction() + 234 + (java.lang.Double)Function.invoke(null, args);

activity是任意的双精度值。我正在考虑可能做得更抽象和一般化一点,就像SoftwareMonkey所做的那样,但目前我对它的方式很满意。三行代码,没有必要的类和接口,还不错。

匿名内部类

假设你想要传入一个带有String参数的函数,该参数返回一个整型。 首先,如果不能重用现有的接口,则必须定义一个接口,该接口的唯一成员是该函数。

interface StringFunction {
    int func(String param);
}

接受指针的方法只接受StringFunction实例,如下所示:

public void takingMethod(StringFunction sf) {
   int i = sf.func("my string");
   // do whatever ...
}

并且会被这样称呼:

ref.takingMethod(new StringFunction() {
    public int func(String param) {
        // body
    }
});

编辑:在Java 8中,你可以用lambda表达式调用它:

ref.takingMethod(param -> bodyExpression);

从Java8开始,您可以使用lambdas,它在官方SE 8 API中也有库。

用法: 您只需要使用带有一个抽象方法的接口。 创建一个实例(你可能想使用java SE 8已经提供的实例),如下所示:

Function<InputType, OutputType> functionname = (inputvariablename) {
... 
return outputinstance;
}

有关更多信息,请查看文档:https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

对于每个“函数指针”,我会创建一个小的函子类来实现你的计算。 定义一个所有类都将实现的接口,并将这些对象的实例传递到更大的函数中。这是“命令模式”和“战略模式”的结合。

@sblundy的例子很好。