jre - java更新




如何在Java中將函數作為參數傳遞? (6)

這個問題在這裡已經有了答案:

是否可以將方法作為參數傳遞給Java方法? 如果是這樣,有人可以引導我嗎? 這似乎並不重要


注意 :以下答案只適用於Java BEFORE Java 8之前的版本。如果您使用的是Java 8,請查找'java 8 lambda表達式'。 這是我在下面描述的語法糖。

例如,一種常見的模式是將其“包裝”在界面中,例如Callable ,然後傳入Callable:

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

這種模式被稱為命令模式

請記住,最好為您的特定用途創建一個界面。 如果您選擇使用可調用的函數,那麼您將使用您期望的任何類型的返回值替換上面的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的基本概念等價於函數指針的概念。


Lambda表達式

為了增加jk。的優秀答案 ,現在可以使用Lambda表達式 (在Java 8中)更輕鬆地傳遞一個方法。 首先,一些背景。 功能接口是一種只有一種抽象方法的接口,但它可以包含任意數量的默認方法 (Java 8中的新增功能)和靜態方法。 如果不使用lambda表達式,lambda表達式可以快速實現抽象方法,而不需要所有不必要的語法。

沒有lambda表達式:

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

使用lambda表達式:

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

以下是關於Lambda表達式的Java教程的摘錄:

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

    返回語句不是表達式; 在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
    }
}

使用::運算符可以縮短上面的例子。

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

Java支持閉包很好。 它只是不支持函數 ,所以用於閉包的語法更加笨拙和笨重:您必須使用方法將所有內容包裝到類中。 例如,

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

將返回一個Runnable對象,其run()方法“關閉”傳入的x ,就像支持一流函數和閉包的任何語言一樣。


你可以使用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);
    }

}

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

public interface Callable<I, O> {

    public O call(I input);

}

我知道這是一個相當老的帖子,但我有另一個稍微簡單的解決方案。 你可以在其中創建另一個類並將其抽象化。 接下來讓抽象方法命名它,無論你喜歡什麼。 在原始類中創建一個將新類作為參數的方法,在此方法中調用抽象方法。 它看起來像這樣。

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