在Java中,如何将一个函数作为另一个函数的参数传递?


当前回答

您可以使用Java反射来做到这一点。该方法将表示为java.lang.reflect.Method的一个实例。

import java.lang.reflect.Method;

public class Demo {

    public static void main(String[] args) throws Exception{
        Class[] parameterTypes = new Class[1];
        parameterTypes[0] = String.class;
        Method method1 = Demo.class.getMethod("method1", parameterTypes);

        Demo demo = new Demo();
        demo.method2(demo, method1, "Hello World");
    }

    public void method1(String message) {
        System.out.println(message);
    }

    public void method2(Object object, Method method, String message) throws Exception {
        Object[] parameters = new Object[1];
        parameters[0] = message;
        method.invoke(object, parameters);
    }

}

其他回答

我知道这是一个相当老的帖子,但我有另一个稍微简单的解决方案。 您可以在其中创建另一个类并使其抽象。接下来,创建一个抽象方法,命名为任何你喜欢的名字。在原来的类中创建一个以新类为参数的方法,在这个方法中调用抽象方法。它看起来是这样的。

public class Demo {

    public Demo(/.../){

    }

    public void view(Action a){
        a.preform();
    }

    /**
     * The Action Class is for making the Demo
     * View Custom Code
     */
    public abstract class Action {

        public Action(/.../){

        }

        abstract void preform();
    }
}

现在您可以执行类似的操作来从类内部调用一个方法。

/...
Demo d = new Demo;
Action a = new Action() {

    @Override
    void preform() {
        //Custom Method Code Goes Here
    }
};

/.../
d.view(a)

就像我说的,我知道它很旧,但我认为这样更容易一些。希望能有所帮助。

Java很好地支持闭包。它只是不支持函数,所以您习惯的闭包语法更加笨拙和笨重:您必须用一个方法将所有内容包装在一个类中。例如,

public Runnable foo(final int x) {
  return new Runnable() {
    public void run() {
      System.out.println(x);
    }
  };
}

将返回一个Runnable对象,其run()方法“关闭”传入的x,就像在任何支持一级函数和闭包的语言中一样。

多亏了Java 8,你不需要执行下面的步骤来将一个函数传递给一个方法,这就是lambdas的作用,请参阅Oracle的Lambda表达式教程。这篇文章的其余部分描述了我们过去为了实现这个功能而不得不做的事情。

通常情况下,您将方法声明为带有单个方法的某个接口,然后传入实现该接口的对象。一个例子是common -collections,其中有Closure、Transformer和Predicate的接口,以及传递这些接口实现的方法。Guava是新的改进的公共集合,你可以在那里找到等价的接口。

例如,commons-collections有org。apache。commons。collections。collectionutils,它有很多静态方法,可以接收传入的对象,随机抽取一个,有一个叫exists,带有这个签名

static boolean exists(java.util.Collection collection, Predicate predicate) 

它接受一个实现接口Predicate的对象,这意味着它必须有一个接受object并返回布尔值的方法。

所以我可以这样调用它:

CollectionUtils.exists(someCollection, new Predicate() {
    public boolean evaluate(Object object) { 
        return ("a".equals(object.toString());
    }
});

它返回true或false,这取决于someCollection是否包含一个谓词为其返回true的对象。

无论如何,这只是一个例子,而common -collections已经过时了。我只是忘了番石榴的等价物。

我使用的命令模式是@jk。提到,添加一个返回类型:

public interface Callable<I, O> {

    public O call(I input);   
}

Lambda表达式

加上jk。的完美回答,现在你可以使用Lambda表达式(在Java 8中)更容易地传递一个方法。函数式接口是具有且仅有一个抽象方法的接口,尽管它可以包含任意数量的默认方法(Java 8新增)和静态方法。lambda表达式可以快速实现抽象方法,如果不使用lambda表达式,则无需使用所有不必要的语法。

没有lambda表达式:

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});

使用lambda表达式:

obj.aMethod(i -> i == 982);

以下是Java Lambda表达式教程的节选:

Syntax of Lambda Expressions A lambda expression consists of the following: A comma-separated list of formal parameters enclosed in parentheses. The CheckPerson.test method contains one parameter, p, which represents an instance of the Person class.Note: You can omit the data type of the parameters in a lambda expression. In addition, you can omit the parentheses if there is only one parameter. For example, the following lambda expression is also valid: p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25 The arrow token, -> A body, which consists of a single expression or a statement block. This example uses the following expression: p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25 If you specify a single expression, then the Java runtime evaluates the expression and then returns its value. Alternatively, you can use a return statement: p -> { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; } A return statement is not an expression; in a lambda expression, you must enclose statements in braces ({}). However, you do not have to enclose a void method invocation in braces. For example, the following is a valid lambda expression: email -> System.out.println(email) Note that a lambda expression looks a lot like a method declaration; you can consider lambda expressions as anonymous methods—methods without a name.


下面是如何使用lambda表达式“传递一个方法”:

注意:这使用了一个新的标准函数接口java.util.function.IntConsumer。

class A {
    public static void methodToPass(int i) { 
        // do stuff
    }
}
import java.util.function.IntConsumer;

class B {
    public void dansMethod(int i, IntConsumer aMethod) {
        /* you can now call the passed method by saying aMethod.accept(i), and it
        will be the equivalent of saying A.methodToPass(i) */
    }
}
class C {
    B b = new B();

    public C() {
        b.dansMethod(100, j -> A.methodToPass(j));   //Lambda Expression here
    }
}

上面的例子可以使用::运算符进一步简化。

public C() {
    b.dansMethod(100, A::methodToPass);
}