Java Lambda

      在〈Java Lambda〉中尚無留言

Lambda 是 Java 8.0 導入的精簡語法,可以大幅縮減程式碼的長度。Lambda 只適用於介面的 SAM 方法。

  SAM

SAM 全名為 Single Abstract Method (單一抽象方法),意思是指一個介面只有一個抽象方法,如下所示。

interface Runnable{
    void run();
}

像這種只有一個抽象方法的介面多不勝數,為什麼 Java 會有這麼多無聊的介面呢? 說穿了只是為了多型而以。

SAM 只針對 interface,不適用於抽象類別。

正規寫法

正規寫法需先產生一個實作 Runnable 的類別,然後再由此類別產生物件,再將此物件塞入 Thread 裏,如下所示。

🔒 底下內容僅限會員閱讀。

立即登入

匿名類別寫法

由 new Runnable(){} 並實作 run 方法, 產生 Runnable 的匿名類別及匿名物件,如下所示。

🔒 底下內容僅限會員閱讀。

立即登入

Lambda 寫法

使用 Lambda 語法不但連匿名類別都不用,甚至連 new 都可省略。

🔒 底下內容僅限會員閱讀。

立即登入

傳入 new Thread 的參數,沒有宣告為 Runnable 物件,而且連函數名稱也沒有,這是因為系統知道 new Thread 所需要的東西就是 Runnable 物件。

這種寫法類似在 new Thread 裏塞入一個函數,等於是把介面當成函數來看待,稱為 functional interface (函數式介面)。

行為 Behavior

底下的代碼就是函數式介面,但 Java 又給了一個特別名稱,叫「行為」(Behavior)。

() -> {
    System.out.println("Lambda");
}

Lambda 不會產生類別

使用 Lambda 不會產生類別,從下面的程式碼中可以驗証得知。使用 Lambda 的片段不可以使用 this.getClass(),但使用匿名類別的片段,可以使用 this.getClass() 取得正確的類別名稱。

🔒 底下內容僅限會員閱讀。

立即登入

Lambda 表示式

Lambda 表示式可以寫成如下

(input) -> {body};

input 及 body 有著多種不同的寫法,請記得底下的說明。

只有一個,可有可無

input 只有一個參數,() 可有可無。

body 只有一行,{} 可有可無。

🔒 底下內容僅限會員閱讀。

立即登入

無或多個,需有 () {}

input 無或多個參數,都需要 ()。

body無或多行,都需要 {}。

🔒 底下內容僅限會員閱讀。

立即登入

只有一行返回值

第一種是使用 {return xxx;},一定要有{}。

🔒 底下內容僅限會員閱讀。

立即登入

第二種是不用 {} 也不需 return,直接寫返回值。

🔒 底下內容僅限會員閱讀。

立即登入

input 參數宣告

input 裏的參數不用宣告型別,也可以雞婆的宣告型別,但宣告型別就一定要加 ()

🔒 底下內容僅限會員閱讀。

立即登入

行為參數化 Behavior Parameterization

說的白話一點,就是函數的參數,可以是另一個函數。

這其實是 C 程式語言一直想解決的一個問題:能不能把「要執行什麼」也當成參數傳給另一個函數?C 語言最後透過函數指標(Function Pointer)實現了這個概念,讓我們可以把一個函數傳進另一個函數,讓它決定「接下來要執行什麼」。

到了 Java,則透過函數式介面(Functional Interface)與 Lambda 表達式,讓這件事情變得更加簡潔、直觀。

將「行為」當成方法的參數傳入,其核心概念是讓方法可以接收另一個方法。Lambda 表達式可以將一段行為傳入方法,使方法的參數可以代表不同的行為,這種設計方式稱為「行為參數化(Behavior Parameterization)」。

底下以 Predicate 介面進行說明。Predicate 是一個需實作 test() 方法的介面,只會回傳 true/false 二個結果。

傳統寫法

傳統的寫法需先產生 MyPredicate 類別,再於主程式產生 a 物件,完整代碼如下

🔒 底下內容僅限會員閱讀。

立即登入

匿名類別

使用匿名類別,可以省略 MyPredicate 的製作。

🔒 底下內容僅限會員閱讀。

立即登入

Lambda 寫法

使用 Lmabda,連實作方法的代碼都可以省略

🔒 底下內容僅限會員閱讀。

立即登入

傳入物件

設定一個 filter 方法,比對 List 裏的所有項目是否大於30,可以將 Predicate c 物件傳入 filter 方法中。

🔒 底下內容僅限會員閱讀。

立即登入

傳入行為

傳入 filter 方法的參數,不再是物件,而是行為(函數)

🔒 底下內容僅限會員閱讀。

立即登入

變型應用

先定義一個 MathOperator 介面,裏面只有一個 operate 抽象方法,然後使用 Lambda 產生 add、sub、multi、div 四個函數式介面,最後傳入 calculate 方法的參數中,如此就可得到不同的計算結果。這等於是把函數傳給 calculate 方法中的參數。

public class JavaApp{
    public static void main(String[] args) {
        MathOperator add = (int x, int y) -> x+y;
        MathOperator sub = (x, y) -> x-y;
        MathOperator multi = (x, y) -> {return x*y;};
        MathOperator div = (x, y) -> x/y;
        int x=100, y=10;
        System.out.printf("相加 : %d\n",calculate(x, y, add));
        System.out.printf("相減 : %d\n",calculate(x, y, sub));
        System.out.printf("相乘 : %d\n",calculate(x, y, multi));
        System.out.printf("相除 : %d\n",calculate(x, y, div));
        MathOperator pow = new MathOperator(){
            @Override
            public int operate(int x, int y) {
                return (int)(Math.pow(x, y));
            }
        };
        System.out.printf("冥次方 : %d\n",calculate(2, 10, pow));
    }
    private static int calculate(int a, int b, MathOperator operator){
       return operator.operate(a, b);
    }
}
interface MathOperator{
    int operate(int x, int y);
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *