Java 8 引入的 Lambda 表達式徹底改變了 Java 的程式設計風格,讓函數式編程成為可能。本文系統整理 Lambda 語法規則、核心函數式介面、方法引用、型別推導與 Stream API 實戰應用。
只有一個抽象方法的介面稱為函數式介面,可隱式轉換為 Lambda 表達式。常見範例:
// 匿名內部類寫法
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {}
});
// Lambda 等價寫法(四種語法變體)
button.addActionListener(e -> System.out.println("Hello"));
button.addActionListener((e) -> System.out.println("Hello"));
button.addActionListener((ActionEvent e) -> System.out.println("Hello"));
button.addActionListener((ActionEvent e) -> { System.out.println("Hello"); return; });
標準形式:(參數列表) -> { 方法體 }
| 規則 | 說明 | 範例 |
|---|---|---|
| 參數型別可省略 | 編譯器可從上下文推導 | (x, y) -> x + y |
| 單一參數括號可省略 | 型別可推導時 | x -> x * 2 |
| 單一陳述式大括號與 return 可省略 | 型別可推導時 | x -> System.out.println(x) |
| 多行陳述式需大括號與 return | (x, y) -> { int z = x + y; return z; } |
java.util.function 套件定義了常用介面:
Consumer<T>:消費型,void accept(T t),如 s -> System.out.println(s)Supplier<T>:供給型,T get()Function<T, R>:函數型,R apply(T t)Predicate<T>:斷言型,boolean test(T t)BiFunction<T, U, R>:雙參數函數Lambda 的進一步簡化,語法:類別::方法名 或 物件::方法名
// 靜態方法引用
Arrays.stream(arr).forEach(Test::sayHello);
// 等價於
Arrays.stream(arr).forEach(s -> Test.sayHello(s));
// 實例方法引用
list.forEach(System.out::println);
// 建構子引用
List<String> list = Stream.of("a", "b").map(String::new).collect(Collectors.toList());
// 陣列建構子引用
String[] arr = list.toArray(String[]::new);
當編譯器無法推導目標型別時,需顯式指定:
Stream<Object> strings = shapeList.stream().<Object>map(s -> s.getColor());
// s.getColor() 回傳 String,但目標流型別為 Object,需 <Object> 指定
Arrays.stream(array) // 陣列
list.stream() // Collection
string.chars() // 字串 -> IntStream
// 聚合
int sum = Arrays.stream(arr).sum();
int sum2 = Arrays.stream(arr).reduce(0, (x, y) -> x + y);
// 轉換與收集
List<Shape> shapes = colorList.stream().map(Shape::new).collect(Collectors.toList());
Set<String> colors = shapes.stream().map(Shape::getColor).collect(Collectors.toSet());
Map<String, Shape> map = shapes.stream().collect(Collectors.toMap(Shape::getColor, s -> s));
// 分組
Map<String, Set<Shape>> grouped = shapes.stream()
.collect(Collectors.groupingBy(Shape::getColor, Collectors.toSet()));
// 就地修改集合
shapes.sort(Comparator.comparing(Shape::getColor));
shapes.removeIf(s -> "Red".equals(s.getColor()));
shapes.replaceAll(s -> new Shape(s.getColor().toUpperCase()));
list.parallelStream().forEach(...); // 多執行緒處理,注意執行緒安全
Lambda 表達式配合 Stream API,讓 Java 程式碼更宣告式、更簡潔。掌握函數式介面、方法引用與收集器是高效使用的關鍵。建議在實際專案中大量練習,體會「告訴電腦做什麼」而非「怎麼做」的思維轉變。