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


当前回答

如果你只有一个不同的行,你可以添加一个参数,比如一个标志和一个If (flag)语句,它调用一行或另一行。

其他回答

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

@sblundy的例子很好。

方法引用,使用::操作符

当方法接受函数接口时,可以在方法参数中使用方法引用。函数接口是任何只包含一个抽象方法的接口。(一个功能接口可以包含一个或多个默认方法或静态方法。)

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中的::(双冒号)操作符。

当在一行中可以执行预定义数量的不同计算时,使用枚举是实现策略模式的一种快速而清晰的方法。

public enum Operation {
    PLUS {
        public double calc(double a, double b) {
            return a + b;
        }
    },
    TIMES {
        public double calc(double a, double b) {
            return a * b;
        }
    }
     ...

     public abstract double calc(double a, double b);
}

显然,策略方法声明以及每个实现的一个实例都定义在一个类/文件中。

如果有人试图传递一个函数,该函数使用一组参数来定义其行为,但使用另一组参数来执行,就像Scheme的:

(define (function scalar1 scalar2)
  (lambda (x) (* x scalar1 scalar2)))

参见Java中参数定义行为的传递函数

在没有函数数组接口的情况下做同样的事情:

class NameFuncPair
{
    public String name;                // name each func
    void   f(String x) {}              // stub gets overridden
    public NameFuncPair(String myName) { this.name = myName; }
}

public class ArrayOfFunctions
{
    public static void main(String[] args)
    {
        final A a = new A();
        final B b = new B();

        NameFuncPair[] fArray = new NameFuncPair[]
        {
            new NameFuncPair("A") { @Override void f(String x) { a.g(x); } },
            new NameFuncPair("B") { @Override void f(String x) { b.h(x); } },
        };

        // Go through the whole func list and run the func named "B"
        for (NameFuncPair fInstance : fArray)
        {
            if (fInstance.name.equals("B"))
            {
                fInstance.f(fInstance.name + "(some args)");
            }
        }
    }
}

class A { void g(String args) { System.out.println(args); } }
class B { void h(String args) { System.out.println(args); } }