首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 8 Lambda 表達式完整指南:函數式介面、方法引用、預設方法、Stream API 實戰

     編輯:Java 綜合教學

Java 8 Lambda 表達式完整指南:函數式介面、方法引用、預設方法、Stream API 實戰

Lambda 表達式是 Java 8 最大亮點,將函數式程式設計引入 Java,讓代碼更簡潔、更具表達力。本文系統梳理函數式介面、Lambda 語法、方法引用、介面預設方法、集合框架增強與 Stream API 核心操作。

一、函數式介面 — Lambda 的載體

  • 定義:有且僅有一個抽象方法的介面 (可含預設/靜態方法)
  • 註解:@FunctionalInterface 編譯期驗證,防止誤添加抽象方法
  • 經典例子:Runnable、Comparator<T>、Callable<V>、Predicate<T>、Function<T,R>、Consumer<T>、Supplier<T>
@FunctionalInterface
public interface MyFunc {
    void execute(String param);  // 唯一抽象方法
    default void log() { System.out.println("預設方法"); } // 允許預設方法
}

二、Lambda 語法

(參數列表) -> 表達式
(參數列表) -> { 語句塊; return 結果; }
形式範例說明
無參無返() -> System.out.println("Hi")Runnable
單參無返(s) -> System.out.println(s)括號可省略:s -> ...
多參有返(a, b) -> a + b隱式返回,無需 return
複雜邏輯(x, y) -> { int z = x+y; return z*2; }需大括號與 return

三、方法引用 — Lambda 的語法糖

格式:類名::方法名 或 實例::方法名 或 類名::new

類型語法對應 Lambda
靜態方法Class::staticMethod(args) -> Class.staticMethod(args)
實例方法obj::instanceMethod(args) -> obj.instanceMethod(args)
任意對象實例方法Class::instanceMethod(obj, args) -> obj.instanceMethod(args)
建構子Class::new(args) -> new Class(args)
// 範例:啟動執行緒
Runnable r1 = () -> System.out.println("Lambda");
Runnable r2 = Demo::staticRun;           // 靜態方法引用
Runnable r3 = new Demo()::instanceRun;   // 實例方法引用
new Thread(r2).start();

四、介面預設方法 — 介面演進的關鍵

  • default 關鍵字定義實現方法,實現類可選擇覆寫
  • 解決「介面添加方法破壞現有實現」的二進位相容性問題
  • 集合框架大量使用:Iterable.forEach(), Collection.stream(), Map.computeIfAbsent() 等
  • 多介面衝突:實現類必須顯式覆寫並選擇調用 InterfaceA.super.method()

五、介面 vs 抽象類 (Java 8 後)

維度介面抽象類
多重實現/繼承支援多實現單繼承
方法實現default/static 方法任意方法
構造子無有
狀態 (欄位)僅 static final 常數任意實例欄位
設計意義行為契約 (like-a)實體層次 (is-a)

六、集合框架增強 — 內部迭代

List users = Arrays.asList(
    new User(20, "張三"), new User(22, "李四"), new User(10, "王五"));

// forEach + Lambda
users.forEach(u -> System.out.println(u.getName() + ":" + u.getAge()));

// 移除條件元素 (Java 8 新增)
users.removeIf(u -> u.getAge() < 18);

// 替換所有元素
users.replaceAll(u -> new User(u.getAge() + 1, u.getName()));

七、Stream API — 宣告式資料處理

特點:無儲存、不修改源、延遲執行 (終端操作觸發)、可並行 (parallelStream())、一次性消費。

核心操作分類

類型操作回傳說明
中間操作filter(Predicate)Stream過濾
map(Function)Stream映射轉換
sorted(Comparator)Stream排序
distinct()Stream去重
終端操作forEach(Consumer)void遍歷消費
collect(Collector)R收集 (toList, toSet, groupingBy...)
count()long計數
reduce()Optional歸約聚合
anyMatch/allMatch/noneMatchboolean匹配判斷

實戰範例

List users = ...;

// 1. 篩選年齡 ≥ 20,取名字轉大寫,收集為 List
List names = users.stream()
    .filter(u -> u.getAge() >= 20)
    .map(u -> u.getName().toUpperCase())
    .collect(Collectors.toList());

// 2. 統計年齡 ≥ 20 的人數
long count = users.stream()
    .filter(u -> u.getAge() >= 20)
    .count();

// 3. 找出最年長者
Optional oldest = users.stream()
    .max(Comparator.comparing(User::getAge));

// 4. 分組:按年齡段分組
Map> groups = users.stream()
    .collect(Collectors.groupingBy(u -> {
        if (u.getAge() < 18) return "青少年";
        else if (u.getAge() < 60) return "成年";
        else return "長者";
    }));

// 5. 並行流處理大數據 (多核 CPU 加速)
List bigData = ...;
bigData.parallelStream()
    .filter(s -> s.length() > 10)
    .collect(Collectors.toList());

八、最佳實踐建議

  1. 優先使用方法引用而非簡單 Lambda,可讀性更高
  2. 避免在 Lambda 中修改外部變數 (需 final/effectively final)
  3. Stream 管道保持純淨,副作用操作放在 forEach 終端
  4. 大數據量才用 parallelStream(),小數據開銷大於收益
  5. 善用 Optional 避免 NPE,而非直接 get()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved