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

是否有可能将方法作为parameter passing给Java方法? 如果是的话,有人可以指导我吗? 这似乎并不重要

注意 :对于Java 8以前版本的Java,下面的答案就足够了。如果使用Java 8,请查找“java 8 lambdaexpression式”。 这是我在下面描述的语法糖。

一个常见的模式是将其“包装”在一个界面中,例如Callable ,然后传递一个Callable:

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

这种模式被称为命令模式 。

请记住,您最好为您的特定用法创build一个界面。 如果您select使用可调用的方法,那么您将使用您期望的任何types的返回值replace上面的T,例如String。

为了回应你的评论,你可以这样说:

 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的基本概念等价于函数指针。

你可以使用Javareflection来做到这一点。 该方法将被表示为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); } } 

Lambdaexpression式

要添加到jk。的优秀答案 ,现在可以使用Lambdaexpression式 (在Java 8中)更简单地传递一个方法。 首先是一些背景。 function接口是一个只有一个抽象方法的接口,尽pipe它可以包含任意数量的默认方法 (Java 8中的新增function)和静态方法。 如果不使用lambdaexpression式,lambdaexpression式可以快速实现抽象方法,而不需要所有不必要的语法。

没有lambdaexpression式:

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

用lambdaexpression式:

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

下面是关于Lambdaexpression式的Java教程的摘录:

Lambdaexpression式的语法

一个lambdaexpression式包含以下内容:

  • 用逗号分隔的括号内的forms参数列表。 CheckPerson.test方法包含一个参数p,它表示Person类的一个实例。

    注意 :您可以省略lambdaexpression式中参数的数据types。 另外,如果只有一个参数,则可以省略括号。 例如,下面的lambdaexpression式也是有效的:

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

  • 一个由单个expression式或语句块组成的主体。 这个例子使用下面的expression式:

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

    如果指定单个expression式,则Java运行时将评估expression式,然后返回其值。 或者,您可以使用返回语句:

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

    返回语句不是一个expression式; 在lambdaexpression式中,必须将括号括在括号({})中。 但是,您不必在大括号中包含void方法调用。 例如,以下是有效的lambdaexpression式:

     email -> System.out.println(email) 

请注意,lambdaexpression式看起来很像一个方法声明; 您可以将lambdaexpression式视为匿名方法 – 没有名称的方法。


以下是如何使用lambdaexpression式“传递方法”:

注意:这使用了一个新的标准function接口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); } 

感谢Java 8,您不需要执行以下步骤将函数传递给方法,这就是lambdaexpression式的用法,请参阅Oracle的Lambda Expression教程 。 这篇文章的其余部分描述了为了实现这个function,我们过去不好的时候必须做的事情。

通常你声明你的方法是用一个单一的方法接受一些接口,然后你传入一个实现了这个接口的对象。 一个例子是commons-collections,其中有Closure,Transformer和Predicate的接口,以及将这些实现传递给它们的方法。 番石榴是新改进的公共collections品,你可以在那里find相应的界面。

所以,例如,commons-collections有org.apache.commons.collections.CollectionUtils,它有很多静态方法把对象传入,随机select一个,还有一个叫做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()); } }); 

并根据someCollection是否包含谓词返回true的对象返回true或false。

无论如何,这仅仅是一个例子,公共collections已经过时了。 我只是忘记在番石榴的相当。

Java支持closures就好了。 它只是不支持函数 ,所以用于闭包的语法更加笨拙和笨重:您必须用方法将所有东西包装在类中。 例如,

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

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

我知道这是一个相当老的post,但我有另一个稍微简单的解决scheme。 你可以在其中创build另一个类,并将其抽象化。 接下来,无论你喜欢什么,抽象方法的名字。 在原始类中创build一个将新类作为参数的方法,在此方法中调用抽象方法。 它会看起来像这样。

 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) 

就像我说的,我知道它的老,但这样我觉得有点容易。 希望它有帮助。

我使用了@jk的命令模式。 提到,增加一个返回types:

 public interface Callable<I, O> { public O call(I input); } 

Java不支持闭包。 但是还有其他的语言如Scala和Groovy在JVM中运行并支持闭包。