others - 在Java,如何将函数作为参数传递?

是否可以将方法作为参数传递到Java方法中?

时间:

注意:如果使用Java 8,在Java 8.之前,以下答案足够了,查找'Java 8Lambda表达式',我下面描述的是语法糖。


public T myMethod(Callable<T> func) {
 return func.call();
}

这种模式被称为命令模式

记住你最好为你的特定用途创建一个接口,


public int methodToPass() { 
 // do something
}

public void dansMethod(int i, Callable<Integer> myFunc) {
 // do something
}

然后调用它,可能使用匿名内部类:


dansMethod(100, new Callable<Integer>() {
 public Integer call() {
 return methodToPass();
 }
});

请记住这不是一个'技巧',这只是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);
 }

}

Lambda表达式可以快速实现抽象方法,如果您不使用Lambda表达式,则不需要所有不必要的语法。

没有lambda表达式:


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

使用lambda表达式:


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


Lambda表达式的语法

lambda表达式由以下内容组成:

  • 逗号分隔的形式参数的逗号分隔列表,CheckPerson.test方法包含一个参数p,它表示Person类的一个实例,

    注意:你可以在lambda表达式中省略参数的数据类型,此外,如果只有一个参数,则可以省略括号,例如下面的lambda表达式也是有效的:

    
    p -> p.getGender() == Person.Sex.MALE 
     && p.getAge() >= 18
     && p.getAge() <= 25
    
    
  • 箭头标记,->

  • 一个由单个表达式或语句块组成的主体,此例子使用以下表达式:

    
    p.getGender() == Person.Sex.MALE 
     && p.getAge() >= 18
     && p.getAge() <= 25
    
    

    如果指定单个表达式,则Java运行时计算该表达式,然后返回它值,或者,也可以使用return语句:

    
    p -> {
     return p.getGender() == Person.Sex.MALE
     && p.getAge() >= 18
     && p.getAge() <= 25;
    }
    
    

    return语句不是表达式; 在lambda表达式中,必须将语句括在大括号({} )中,但是,你不必在大括号中包含void方法调用,例如以下是有效的lambda表达式:

    
    email -> System.out.println(email)
    
    

注意,lambda表达式看起来很像一个方法声明; 你可以将lambda表达式视为匿名方法,即不带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 aFunction)
 {
 //do stuff
 }
}


class C
{
 B b = new B();

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


上面的例子可以通过使用::运算符


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

免责声明:我无法在计算机上运行Java 8,因为它不支持Windows XP ,这个答案中包含的任何示例都可能有错误,因为我不能测试它们。

通常,你将方法声明为带有单个方法的接口,然后传递一个实现该接口的对象。 在commons-collections中有一个示例,你可以在其中为闭包,变压器和谓词以及你通过实现的方法提供接口。 Guava 是新的改进的commons-collections,你可以在那里找到等价的接口。

例如commons-collections有 org.apache.commons.collections.CollectionUtils,,它有大量的静态方法,它接受对象传入,随机拾取一个,有一个带有这个签名的调用:


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

它需要一个实现接口谓词的对象,这意味着它必须有一个方法来获取一些对象并返回一个布尔值。

这样我就可以这样称呼它:


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

根据 someCollection 是否包含谓词返回为真的对象,它返回真或者假。

总之,这只是一个例子,commons-collections已经过时了。 我只是忘记了 Guava 中的等价。


public interface Callable<I, O> {

 public O call(I input);

}

Java只支持闭包,它不支持函数,所以用于闭包的语法更加容易和更大: 例如,


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

在原始类中,将新类作为参数作为参数,在此方法中调用抽象方法,它看起来像这样。


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没有( 还还还) 支持闭包。 但是还有其他语言如 Scala 和Groovy在JVM中运行并支持闭包。

...