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