我有一个方法,大约有十行代码。我想创建更多的方法来做完全相同的事情,除了一个会改变一行代码的小计算。这是一个传递函数指针来替换这一行的完美应用程序,但是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匹配。如果不这样做,编译器将发出一个错误。
其他回答
你也可以这样做(在一些罕见的情况下是有意义的)。问题(这是一个大问题)是您失去了使用类/接口的所有类型安全性,并且您必须处理方法不存在的情况。
它确实有一个“好处”,即您可以忽略访问限制并调用私有方法(示例中没有显示,但您可以调用编译器通常不允许您调用的方法)。
同样,这在很少的情况下是有意义的,但在那些情况下,这是一个很好的工具。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main
{
public static void main(final String[] argv)
throws NoSuchMethodException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
final String methodName;
final Method method;
final Main main;
main = new Main();
if(argv.length == 0)
{
methodName = "foo";
}
else
{
methodName = "bar";
}
method = Main.class.getDeclaredMethod(methodName, int.class);
main.car(method, 42);
}
private void foo(final int x)
{
System.out.println("foo: " + x);
}
private void bar(final int x)
{
System.out.println("bar: " + x);
}
private void car(final Method method,
final int val)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
method.invoke(this, val);
}
}
方法引用,使用::操作符
当方法接受函数接口时,可以在方法参数中使用方法引用。函数接口是任何只包含一个抽象方法的接口。(一个功能接口可以包含一个或多个默认方法或静态方法。)
IntBinaryOperator是一个功能接口。它的抽象方法applyAsInt接受两个int作为参数,并返回一个int。数学。Max也接受两个int型并返回一个int型。在这个例子中,A.method(Math::max);使参数。applyAsInt将它的两个输入值发送给Math。返回Math.max的结果。
import java.util.function.IntBinaryOperator;
class A {
static void method(IntBinaryOperator parameter) {
int i = parameter.applyAsInt(7315, 89163);
System.out.println(i);
}
}
import java.lang.Math;
class B {
public static void main(String[] args) {
A.method(Math::max);
}
}
一般来说,你可以使用:
method1(Class1::method2);
而不是:
method1((arg1, arg2) -> Class1.method2(arg1, arg2));
它是:
method1(new Interface1() {
int method1(int arg1, int arg2) {
return Class1.method2(arg1, agr2);
}
});
有关更多信息,请参阅Java 8和Java语言规范§15.13中的::(双冒号)操作符。
谷歌Guava库正在变得非常流行,它有一个通用的Function和Predicate对象,它们已经在API的许多部分中使用了这些对象。
你可能也会对Java 7中涉及闭包的工作感兴趣:
Java闭包的当前状态是什么?
http://gafter.blogspot.com/2006/08/closures-for-java.html http://tech.puredanger.com/java7/#closures
没有一个Java 8的答案给出了一个完整的、内聚的例子,所以它就来了。
声明接受“函数指针”的方法如下:
void doCalculation(Function<Integer, String> calculation, int parameter) {
final String result = calculation.apply(parameter);
}
通过为函数提供lambda表达式来调用它:
doCalculation((i) -> i.toString(), 2);
推荐文章
- Java中的@UniqueConstraint注释
- 如何在清洁模式下运行eclipse ?如果我们这样做会发生什么?
- 获取java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory异常
- Java中的正则表达式命名组
- c#和Java的主要区别是什么?
- 什么是NullPointerException,我如何修复它?
- 在Java中使用“final”修饰符
- 无法在Flutter上找到捆绑的Java版本
- 如何在Kotlin解析JSON ?
- 如何在新的材质主题中改变背面箭头的颜色?
- 如何设置OkHttp连接超时
- 用于桌面应用程序的Swing vs JavaFx
- 为什么这个Java程序会终止,尽管它显然不应该(也没有)终止?
- 使用split("|")按管道符号拆分Java字符串
- 当内存不足导致抛出OutOfMemoryError时会发生什么?