首页 文章

如何在Java中将函数作为参数传递? [重复]

提问于
浏览
341

这个问题在这里已有答案:

是否可以将方法作为参数传递给Java方法?如果是这样,有人可以指导我吗?这似乎并不重要

8 回答

  • -10

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

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

    Java(尚未)支持闭包 . 但是还有其他语言,如Scala和Groovy,它们在JVM中运行并支持闭包 .

  • 83

    Java 8及以上版本

    使用Java 8 lambda表达式,如果您的类或接口只有一个方法,例如:

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

    然后在任何使用MyInterface的地方,您可以替换lambda表达式:

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

    例如,您可以非常快速地创建新线程:

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

    并使用method reference syntax使其更清洁:

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

    如果没有lambda表达式,最后两个示例将如下所示:

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

    在Java 8之前

    一个常见的模式是在界面内'wrap',例如 Callable ,然后你传入一个Callable:

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

    这种模式称为Command Pattern .

    请记住,最好为特定用途创建界面 . 如果您选择使用callable,那么您将使用您期望的任何类型的返回值替换上面的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的基本概念等价于函数指针 .

  • 14

    您可以使用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);
        }
    
    }
    
  • 379

    Lambda表达式

    要添加到jk.'s excellent answer,您现在可以使用Lambda Expressions(在Java 8中)更轻松地传递方法 . 首先,一些背景 . 功能接口是一个只有一个抽象方法的接口,尽管它可以包含任意数量的default methods(Java 8中的新增功能)和静态方法 . 如果不使用lambda表达式,lambda表达式可以快速实现抽象方法,而不需要所有不必要的语法 .

    没有lambda表达式:

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

    使用lambda表达式:

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

    以下是the Java tutorial on Lambda Expressions的摘录:

    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表达式视为匿名方法 - 没有名称的方法 .


    以下是使用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
        }
    }
    

    使用:: operator可以进一步缩短上面的示例 .

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

    感谢Java 8,你不要使用lambdas,请参阅Oracle's Lambda Expression tutorial . 本文的其余部分描述了我们过去在过去的糟糕时期必须要做的事情,以实现此功能 .

    通常,您将方法声明为使用单个方法接受某个接口,然后传入实现该接口的对象 . 一个例子是在commons-collections中,你有Closure,Transformer和Predicate的接口,以及你将它们的实现传递到的方法 . Guava是新改进的commons-collections,你可以在那里找到相应的接口 .

    例如,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的对象 .

    无论如何,这只是一个例子,公共收藏已经过时了 . 我忘记了 Guava 中的等价物 .

  • 4

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

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

    将返回一个传入的 run() 方法"closes over"的Runnable对象,就像支持第一类函数和闭包的任何语言一样 .

  • 4

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

    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)
    

    就像我说的那样,我知道它已经老了,但这种方式我觉得有点容易 . 希望能帮助到你 .

相关问题