Java 8 引入的 Lambda 表達式是語言發展史上的里程碑,它讓我們能以更簡潔、函數式的風格編寫代碼。本文將從替換匿名內部類切入,系統講解 Lambda 語法、方法引用、變量捕獲規則以及接口默認/靜態方法的新特性。
在 Java 8 之前,實現單一方法接口(如 Runnable、Comparator)通常需要匿名內部類,代碼冗長且難讀。Lambda 表達式完美解決了這個問題。
// 傳統匿名內部類寫法
new Thread(new Runnable() {
public void run() {
System.out.println("hello world!!!");
}
}).start();
// Lambda 表達式寫法
new Thread(() -> System.out.println("hello lambda!!!")).start();
List<String> strList = Arrays.asList("zhaojigang", "nana", "tianya");
// 傳統寫法
Collections.sort(strList, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
// Lambda 寫法(類型推斷自動識別 s1、s2 為 String)
Collections.sort(strList, (s1, s2) -> s1.compareTo(s2));
標準語法:(參數列表) -> { 方法體 }
()(x, y)x(可省略括號){} 和 return 關鍵字{} 包裹並顯式 return當 Lambda 體僅調用一個現有方法時,可用方法引用進一步簡化代碼。語法為 ::。
// Lambda Collections.sort(strList, (s1, s2) -> s1.compareTo(s2)); // 方法引用:類::實例方法(第一個參數作為調用者) Collections.sort(strList, String::compareTo); // Lambda strList.forEach(x -> System.out.println(x)); // 方法引用:對象::實例方法 strList.forEach(System.out::println);
三種常見形式對照表:
| 形式 | 語法 | 等價 Lambda |
|---|---|---|
| 對象::實例方法 | obj::method | (args) -> obj.method(args) |
| 類::靜態方法 | Class::staticMethod | (args) -> Class.staticMethod(args) |
| 類::實例方法 | Class::instanceMethod | (obj, args) -> obj.instanceMethod(args) |
Lambda 表達式只能捕獲 final 或實際上 final 的局部變量(即變量初始化後不再修改)。
原因分析: 這是為了防止多線程環境下的競態條件。若 Lambda 在獨立線程中運行,而外部方法修改同一變量,將導致不可預期的行為。這種機制稱為「閉包」。
Java 8 允許接口定義 default 實例方法和 static 靜態方法,實現類無需強制實現,極大便利了舊接口擴展。
public interface LambdaInterface {
// 默認方法
default void defaultMethod() {
System.out.println("default 方法");
}
// 靜態方法
static void staticMethod() {
System.out.println("static 方法");
}
}
// 使用
public class TestInterface implements LambdaInterface {
public static void main(String[] args) {
LambdaInterface test = new TestInterface();
test.defaultMethod(); // 調用默認方法
LambdaInterface.staticMethod(); // 調用靜態方法
}
}
應用場景: 在不破壞現有實現類的前提下,為發布已久的接口添加新功能(如 Collection.stream())。