在Java中如何将函数作为参数传递?

在Java中如何将函数作为参数传递?,java,Java,在Java中,如何将一个函数作为另一个函数的参数传递?多亏了Java 8,将函数传递给方法不需要执行以下步骤,这就是lambda的用途,请参阅。这篇文章的其余部分描述了在过去糟糕的日子里,为了实现这个功能,我们必须做些什么 通常,将方法声明为使用单个方法获取某个接口,然后传入实现该接口的对象。例如,在commons集合中,您有闭包、转换器和谓词的接口,以及将这些接口的实现传递到的方法。Guava是新改进的commons集合,您可以在那里找到等价的接口 例如,commons collections

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

多亏了Java 8,将函数传递给方法不需要执行以下步骤,这就是lambda的用途,请参阅。这篇文章的其余部分描述了在过去糟糕的日子里,为了实现这个功能,我们必须做些什么

通常,将方法声明为使用单个方法获取某个接口,然后传入实现该接口的对象。例如,在commons集合中,您有闭包、转换器和谓词的接口,以及将这些接口的实现传递到的方法。Guava是新改进的commons集合,您可以在那里找到等价的接口

例如,commons collections有org.apache.commons.collections.CollectionUtils,它有很多静态方法,这些方法接收传入的对象,随机选取一个,有一个调用exists的方法,具有以下签名:

static boolean exists(java.util.Collection collection, Predicate predicate) 
它接受一个实现接口谓词的对象,这意味着它必须有一个接受某个对象并返回布尔值的方法

所以我可以这样称呼它:

CollectionUtils.exists(someCollection, new Predicate() {
    public boolean evaluate(Object object) { 
        return ("a".equals(object.toString());
    }
});
根据
someCollection
是否包含谓词返回true的对象,它返回true或false

无论如何,这只是一个例子,commons集合已经过时了。我只是忘记了番石榴的等价物。

Java8及以上版本 使用Java 8+lambda表达式,如果您的类或接口只有一个抽象方法(有时称为a),例如:

public interface MyInterface {
    String doSomething(int param1, String param2);
}
然后,在使用MyInterface的任何地方,都可以替换lambda表达式:

class MyClass {
    public MyInterface myInterface = (p1, p2) -> { return p2 + p1; };
}
p.getGender() == Person.Sex.MALE 
    && p.getAge() >= 18
    && p.getAge() <= 25
email -> System.out.println(email)
例如,您可以非常快速地创建新线程:

new Thread(() -> someMethod()).start();
并使用以下工具使其更干净:

new Thread(this::someMethod).start();
如果没有lambda表达式,最后两个示例如下所示:

new Thread(new Runnable() { someMethod(); }).start();
Java 8之前 一种常见的模式是将其“包装”在接口中,例如
Callable
,然后传入一个Callable:

public T myMethod(Callable<T> func) {
    return func.call();
}
public myt方法(可调用func){
返回函数调用();
}
这种模式被称为

请记住,最好为您的特定用途创建一个接口。如果您选择使用callable,那么您将使用您期望的任何类型的返回值(如String)替换上面的T

对于您在下面的评论,您可以说:

public int methodToPass() { 
        // do something
}

public void dansMethod(int i, Callable<Integer> myFunc) {
       // do something
}
public int methodToPass(){
//做点什么
}
公共无效dansMethod(int i,可调用myFunc){
//做点什么
}
然后调用它,可能使用匿名内部类:

dansMethod(100, new Callable<Integer>() {
   public Integer call() {
        return methodToPass();
   }
});
dansMethod(100,新的可调用(){
公共整数调用(){
返回methodToPass();
}
});

请记住,这不是一个“把戏”。它只是java与函数指针的基本概念等价物。

您可以使用java反射来实现这一点。该方法将表示为的实例


Java还不支持闭包。但是还有其他语言,比如Java和Groovy,它们在JVM中运行,并且确实支持闭包。

Java对闭包的支持非常好。它只是不支持函数,所以您用于闭包的语法要复杂得多:您必须用一个方法将所有内容封装在一个类中。比如说,

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

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

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

public interface Callable<I, O> {

    public O call(I input);   
}
公共接口可调用{
公共O呼叫(I输入);
}

我知道这是一篇相当老的帖子,但我有另一个稍微简单一点的解决方案。 您可以在中创建另一个类并将其抽象。接下来,创建一个抽象方法,可以随意命名。在原始类中创建一个以新类为参数的方法,在此方法中调用抽象方法。它看起来像这样

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)
就像我说的,我知道它很古老,但我觉得这样比较容易。希望有帮助。

Lambda Expressions
要添加到,现在可以更容易地使用传递方法(在Java8中)。首先是一些背景。函数接口是一个只有一个抽象方法的接口,尽管它可以包含任意数量的(Java8中新增的)和静态方法。lambda表达式可以快速实现抽象方法,如果不使用lambda表达式,则不需要所有不必要的语法

没有lambda表达式:

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});
obj.aMethod(i -> i == 982);
使用lambda表达式:

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});
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
    
    如果指定一个表达式,Java运行时将对该表达式求值,然后返回其值。或者, 您可以使用return语句:

    p -> {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
    
请注意,lambda表达式看起来很像方法声明; 可以将lambda表达式视为匿名方法。 没有名字


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

class MyClass {
    public MyInterface myInterface = (p1, p2) -> { return p2 + p1; };
}
p.getGender() == Person.Sex.MALE 
    && p.getAge() >= 18
    && p.getAge() <= 25
email -> System.out.println(email)
注意:这使用了一个新的标准功能接口


上面的示例可以使用


您可以传递一个对象,该对象已定义了一些要用作参数的方法。有关如何使用Lambda函数的更多答案,或将其作为参数传递:。您是否能够显示要传递到的确切内容