本文翻译自:How to pass a function as a parameter in Java? [duplicate]


This question already has an answer here: 这个问题在这里已有答案:

  • Java Pass Method as Parameter 15 answers Java Pass方法作为参数 15答案


Is it possible to pass a method into a Java method as a parameter? 是否可以将方法作为参数传递给Java方法? If so, could someone please guide me? 如果是这样,有人可以指导我吗? This doesn't seem trivial 这似乎并不重要


#1楼

参考:https://stackoom.com/question/Jevb/如何在Java中将函数作为参数传递-重复


#2楼

I used the command pattern that @jk. 我使用了@jk的命令模式。 mentioned, adding a return type: 提到,添加一个返回类型:

public interface Callable<I, O> {

    public O call(I input);   
}

#3楼

I know this is a rather old post but I have another slightly simpler solution. 我知道这是一个相当古老的帖子,但我有另一个稍微简单的解决方案。 You could create another class within and make it abstract. 您可以在其中创建另一个类并使其成为抽象类。 Next make an Abstract method name it whatever you like. 接下来,使用任何您喜欢的方法将Abstract方法命名为。 In the original class make a method that takes the new class as a parameter, in this method call the abstract method. 在原始类中创建一个以新类作为参数的方法,在此方法中调用抽象方法。 It will look something like this. 它看起来像这样。

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();
    }
}

Now you can do something like this to call a method from within the class. 现在你可以做类似的事情从类中调用一个方法。

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

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

/.../
d.view(a)

Like I said I know its old but this way I think is a little easier. 就像我说的那样,我知道它已经老了,但这种方式我觉得有点容易。 Hope it helps. 希望能帮助到你。


#4楼

Lambda Expressions Lambda表达式

To add on to jk.'s excellent answer , you can now pass a method more easily using Lambda Expressions (in Java 8). 要添加到jk。的优秀答案 ,您现在可以使用Lambda Expressions (在Java 8中)更轻松地传递方法。 First, some background. 首先,一些背景。 A functional interface is an interface that has one and only one abstract method, although it can contain any number of default methods (new in Java 8) and static methods. 功能接口是一个只有一个抽象方法的接口,尽管它可以包含任意数量的默认方法 (Java 8中的新方法 )和静态方法。 A lambda expression can quickly implement the abstract method, without all the unnecessary syntax needed if you don't use a lambda expression. 如果不使用lambda表达式,lambda表达式可以快速实现抽象方法,而不需要所有不必要的语法。

Without lambda expressions: 没有lambda表达式:

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

With lambda expressions: 使用lambda表达式:

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

Here is an excerpt from the Java tutorial on Lambda Expressions : 以下是Lambda表达式Java教程的摘录:

Syntax of Lambda Expressions Lambda表达式的语法

A lambda expression consists of the following: lambda表达式包含以下内容:

  • 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.CheckPerson.test方法包含一个参数p,它表示Person类的实例。

    Note : You can omit the data type of the parameters in a lambda expression.注意 :您可以省略lambda表达式中参数的数据类型。In addition, you can omit the parentheses if there is only one parameter.此外,如果只有一个参数,则可以省略括号。For example, the following lambda expression is also valid:例如,以下lambda表达式也是有效的:

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. 如果指定单个表达式,则Java运行时将计算表达式,然后返回其值。 Alternatively, you can use a return statement: 或者,您可以使用return语句:

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

A return statement is not an expression; return语句不是表达式; in a lambda expression, you must enclose statements in braces ({}). 在lambda表达式中,必须将语句括在大括号({})中。 However, you do not have to enclose a void method invocation in braces. 但是,您不必在大括号中包含void方法调用。 For example, the following is a valid lambda expression: 例如,以下是有效的lambda表达式:

email -> System.out.println(email)

Note that a lambda expression looks a lot like a method declaration; 请注意,lambda表达式看起来很像方法声明; you can consider lambda expressions as anonymous methods—methods without a name. 您可以将lambda表达式视为匿名方法 - 没有名称的方法。


Here is how you can "pass a method" using a lambda expression: 以下是使用lambda表达式“传递方法”的方法:

Note: this uses a new standard functional interface, java.util.function.IntConsumer . 注意:这使用新的标准功能接口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
    }
}

The above example can be shortened even more using the :: . 使用::运算符可以进一步缩短上面的示例。

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

#5楼

Thanks to Java 8 you don't need to do the steps below to pass a function to a method, that's what lambdas are for, see Oracle's Lambda Expression tutorial . 感谢Java 8,您不需要执行以下步骤将函数传递给方法,这就是lambdas的用途,请参阅Oracle的Lambda Expression教程 The rest of this post describes what we used to have to do in the bad old days in order to implement this functionality. 本文的其余部分描述了我们过去在过去的糟糕时期必须要做的事情,以实现此功能。

Typically you declare your method as taking some interface with a single method, then you pass in an object that implements that interface. 通常,您将方法声明为使用单个方法接受某个接口,然后传入实现该接口的对象。 An example is in commons-collections, where you have interfaces for Closure, Transformer, and Predicate, and methods that you pass implementations of those into. 一个例子是在commons-collections中,你有Closure,Transformer和Predicate的接口,以及你将它们的实现传递到的方法。 Guava is the new improved commons-collections, you can find equivalent interfaces there. Guava是新改进的commons-collections,你可以在那里找到相应的接口。

So for instance, commons-collections has org.apache.commons.collections.CollectionUtils, which has lots of static methods that take objects passed in, to pick one at random, there's one called exists with this signature: 因此,例如,commons-collections有org.apache.commons.collections.CollectionUtils,它有许多传入对象的静态方法,随机选择一个,有一个带有此签名的exists存在:

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

It takes an object that implements the interface Predicate, which means it has to have a method on it that takes some Object and returns a boolean. 它需要一个实现接口Predicate的对象,这意味着它必须有一个方法,它接受一些Object并返回一个布尔值。

So I can call it like this: 所以我可以这样称呼它:

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

and it returns true or false depending on whether someCollection contains an object that the predicate returns true for. 并且它返回true或false,具体取决于someCollection是否包含谓词返回true的对象。

Anyway, this is just an example, and commons-collections is outdated. 无论如何,这只是一个例子,公共收藏已经过时了。 I just forget the equivalent in Guava. 我忘记了番石榴中的等价物。


#6楼

Java 8 and above Java 8及以上版本

Using Java 8+ lambda expressions, if you have a class or interface with only a single abstract method (sometimes called a SAM type ), for example: 使用Java 8+ lambda表达式,如果您的类或接口只有一个抽象方法(有时称为SAM类型 ),例如:

public interface MyInterface {
    String doSomething(int param1, String param2);
}

then anywhere where MyInterface is used, you can substitute a lambda expression: 然后在任何使用MyInterface的地方,您可以替换lambda表达式:

class MyClass {
    public MyInterface myInterface = (p1, p2) -> { return p2 + p1; };
}

For example, you can create a new thread very quickly: 例如,您可以非常快速地创建新线程:

new Thread(() -> someMethod()).start();

And use the method reference syntax to make it even cleaner: 并使用方法参考语法使其更清晰:

new Thread(this::someMethod).start();

Without lambda expressions, these last two examples would look like: 如果没有 lambda表达式,最后两个示例将如下所示:

new Thread(new Runnable() { someMethod(); }).start();

Before Java 8 在Java 8之前

A common pattern would be to 'wrap' it within an interface, like Callable , for example, then you pass in a Callable: 一个常见的模式是将它“包装”在一个接口中,例如Callable ,然后传入一个Callable:

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

This pattern is known as the Command Pattern . 此模式称为命令模式

Keep in mind you would be best off creating an interface for your particular usage. 请记住,最好为特定用途创建界面。 If you chose to go with callable, then you'd replace T above with whatever type of return value you expect, such as String. 如果您选择使用callable,那么您将使用您期望的任何类型的返回值替换上面的T,例如String。

In response to your comment below you could say: 根据您的评论,您可以说:

public int methodToPass() { 
        // do something
}

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

then call it, perhaps using an anonymous inner class: 然后调用它,也许使用匿名内部类:

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

Keep in mind this is not a 'trick'. 请记住,这不是一个“技巧”。 It's just java's basic conceptual equivalent to function pointers. 它只是java的基本概念等价于函数指针。