Java 長期被視為純命令式語言——通過語句改變程序狀態。但函數式編程(FP)強調「表達式計算」而非「命令執行」,核心優勢在於模組化:將邏輯拆解為更小、更通用、可組合的單元。本文聚焦兩大 FP 基石——閉包與高階函數,並通過 Apache Commons Functor 庫在 Java 中落地實踐。
你早已在用閉包了——每個實現 Runnable、Comparator 的匿名類本質都是閉包:
Runnable worker = new Runnable() {
public void run() { parseData(); } // 封閉了 parseData 調用
};
executor.execute(worker); // 高階函數:接收函數對象並執行
Collections.sort(list, comparator) 同理:Comparator 是閉包,sort 是高階函數。
由庫提供通用接口(如 BinaryPredicate),業務代碼實現之:
// 價格比較器
class PriceComparator implements Comparator {
public int compare(Object o1, Object o2) {
return ((SETLItem)o1).getPrice() - ((SETLItem)o2).getPrice();
}
}
// 組裝:IsGreaterThanOrEqual 是庫提供的 BinaryPredicate 實現
BinaryPredicate bp = new IsGreaterThanOrEqual(new PriceComparator());
bp.test(item1, item2); // 執行比較
優勢:邏輯封裝為對象,可任意傳遞、重用、組合。
庫提供原子操作(Multiply、Subtract、Constant、Identity 等),通過適配器(RightBoundFunction)與組合器(CompositeUnaryFunction、UnaryCompositeBinaryFunction)拼裝複雜邏輯:
// 計算淨價 = (標價 * (1-折扣率)) * (1+稅率)
UnaryFunction calcDiscountedPrice = new RightBoundFunction(new Multiply(), 1 - discountRate);
UnaryFunction calcTax = new RightBoundFunction(new Multiply(), 1 + taxRate);
CompositeUnaryFunction calcNetPrice = new CompositeUnaryFunction(calcTax, calcDiscountedPrice);
Double netPrice = calcNetPrice.evaluate(item.getPrice());
這正是 Currying(柯里化) 與 函數組合 的 Java 實踐。
需求:類別 A 單價 ≥ 100 或 類別 B 單價 ≥ 200 才可打折。
// 原子謂詞
UnaryFunction getItemCat = obj -> ((SETLItem)obj).getCategory();
UnaryFunction getItemPrice = obj -> new Double(((SETLItem)obj).getPrice());
Constant catA = new Constant("A"), catB = new Constant("B");
Constant usd100 = new Constant(100.0), usd200 = new Constant(200.0);
// 組合:屬於 A 且 價格≥100
BinaryPredicateUnaryPredicate belongsToCatA =
new BinaryPredicateUnaryPredicate(new UnaryCompositeBinaryPredicate(new IsEqual(), getItemCat, catA));
BinaryPredicateUnaryPredicate moreThanUSD100 =
new BinaryPredicateUnaryPredicate(new UnaryCompositeBinaryPredicate(new IsGreaterThanOrEqual(), getItemPrice, usd100));
UnaryAnd catAAndPrice = new UnaryAnd(belongsToCatA, moreThanUSD100);
// 同理構建 catBAndPrice...
// 最終規則:(A且≥100) 或 (B且≥200)
UnaryPredicate isEligibleForDiscount = new UnaryOr(catAAndPrice, catBAndPrice);
// 使用
if (isEligibleForDiscount.test(item)) { ... }
規則對象清晰可視、動態可組裝、極易單元測試——這就是 FP 帶來的模組化紅利。
外部迭代器(Iterator)由調用者控制遍歷;內部迭代器由集合內部遍歷,調用者只提供「單元處理邏輯」(閉包):
// 篩選價格≥100 的商品並求和
FilteredIterator fi = new FilteredIterator(items.iterator(), moreThanUSD100);
Summer summer = new Summer(); // 實現 UnaryProcedure,累加價格
Algorithms.foreach(fi, summer); // 高階函數:內部遍歷並應用閉包
int total = summer.getSum();
優勢:遍歷邏輯可復用、支持鏈式過濾、可並行化、無邊界檢查樣板代碼。
用 UnaryPredicate 隱式定義集合,集合運算化為邏輯組合:
public static UnaryPredicate union(UnaryPredicate a, UnaryPredicate b) {
return new UnaryOr(a, b); // 並集 = 或
}
public static UnaryPredicate intersection(UnaryPredicate a, UnaryPredicate b) {
return new UnaryAnd(a, b); // 交集 = 和
}
public static UnaryPredicate difference(UnaryPredicate a, UnaryPredicate b) {
return new UnaryAnd(a, new UnaryNot(b)); // 差集 = a 且 非 b
}
無需物化集合元素,即可進行無限大集合的邏輯運算。
閉包與高階函數並非學院派玩具,它們早已潛伏在 Java 標準庫(Runnable、Comparator、Visitor 模式)中。Apache Commons Functor 等庫將其系統化、組件化,讓我們能以聲明式、組合式風格編寫業務規則、集合操作、控制流邏輯。在 Java 8+ 時代,Lambda 與 Stream API 更將這一範式推向主流——但理解其底層原理,依然是寫出優雅、可維護代碼的關鍵。