Lambda 運算式以及方法參考
Java 8 的新特性筆記,重點講的是:
- Lambda 函式式介面
- 方法參考
- Steam 流
Lambda 運算式
Lambda 的基礎使用不記錄,記錄 JDK 8 實戰 書上的一些底層和核心筆記,
行為引數化
一個貫徹 Lambda 運算式的一個模式、編程規范,
陳述句拆解:
- 行為:就是一個方法或函式
- 引數化:將原來的具體行為,變成一個引數,這個行為就是可變的,適用于多種場景,
主要的思想是:
eg:在某一個業務場景中,有一段業務代碼,可能需要對一個引數進行一些主要的篩選判斷,最后符合條件的才能添加到串列中,
// 過濾蘋果的主要方法
// Predicate 比較
public static List<Apple> filterApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory){
if(條件篩選){ // 是否符合被篩選的條件
result.add(apple);
}
}
return result;
}
通過上面這段代碼,可以看到,這段代碼的核心處理起始只有條件篩選這塊,通過篩選后最后回傳一個 boolean 值,為 ture 才能將蘋果添加到串列中最侄訓傳,
所以條件篩選的可能有許多不同的具體實作,但是毋庸置疑的是最終都需要回傳一個 boolean 值來決定是否滿足將蘋果添加至串列的操作,
所以我們將條件篩選這個行為引數化,來優化代碼,并使其更好擴展和維護,具體的實作可以直接百度 行為引數化 的詳細介紹,
主要是將這個行為引數化的目的,
Java 8 內置的一些常用函式式介面:
大部分日常能用到的在:java.util.function 包下,
注意:函式式介面一般會在類上加上注解 @FunctionalInterface 標識這個是函式式介面,
Lambda 運算式的使用前提是函式式介面,
Lambda 的型別檢查、型別推斷以及限制
型別檢查:
型別檢查很好理解,根據使用 Lambda 的背景關系(例如,接受它傳遞的方法的引數,或者接受它的值的區域變數)推斷出來的,背景關系中使用 Lambda 的型別稱為 目標型別 (就是使用哪個具體的類使用Lambda),根據目標型別(肯定是一個函式式介面)中的抽象方法簽名來對應 Lambda 運算式的簽名(包括抽象方法中宣告的 throws 例外),檢查這個 Lambda 運算式是否符合規范,
特殊的 void 兼容規則:
如果一個Lambda的主體是一個陳述句運算式, 它就和一個回傳 void 的函式描述符兼容(當然需要引數串列也兼容),
eg:以下兩行都是合法的,盡管 List 的 add 方法回傳了一個boolean ,而不是 Consumer 背景關系( T -> void )所要求的 void,
List<String> stringList = new ArrayList<>();
// Predicate回傳了一個boolean
Predicate<String> predicate = s -> stringList.add(s);
// Consumer回傳了一個void
Consumer<String> consumer = s -> stringList.add(s);
型別推斷:
使用 Lambda 運算式,如果至少有一個引數,則可以顯示的說明引數的具體型別,同時也可以不顯示說明,只寫形參名,則會觸發 Java 編譯器的型別推斷機制,根據背景關系來推斷 Lambda 運算式的引數型別,
注意:如果只有一個引數還可以省去引數兩邊的括號,
限制:使用區域變數
Lambda 運算式允許使用自由變數(實體變數,靜態變數)以及區域變數,但是在使用區域變數時有限制,
我們必須保證 Lambda 運算式參考的區域變數最終是 final,也就是說使用的是區域變數的副本,而不是直接去訪問原始變數,
因為區域變數存在堆疊中,這個和 Lambda 執行時執行緒安全相關,
在使用實體變數時,可以改變賦值(參考地址),因為這些變數保存在堆中,而堆是在執行緒之間共享的
方法參考
Java 8 的另一個功能:方法參考,某些 Lambda 的快捷寫法,
基本思想:如果 Lambda 代表的只是 “直接呼叫這個方法”,可以直接用名稱呼叫它,而不是去描述如何呼叫,
使用方法:目標參考 :: 方法名稱
復合 Lambda 運算式的有用方法
例如:Comparator、Function 和 Predicate 都提供了允許你進行復合的方法,
比較器復合(Comparator)
List<Apple> inventory = Arrays.asList(Apple...);
-
逆序
inventory.sort(Comparator.comparing(Apple::getWeight).reversed()); -
比較器鏈:thenComparing() 如果一樣,則按照指定的規則排序
inventory.sort(Comparator.comparing(Apple::getWeight).thenComparing(Apple::getColor));
謂詞復合(Predicate)
介面包含三個默認方法:negate、and 和 or,重用已有的 Predicate 來創建更復雜的謂詞,
redApple 是現有的 Predicate 的實體,
-
negate:
表示此謂詞的邏輯否定的謂詞,
Predicate<Apple> notRedApple = redApple.negate();-- > 蘋果不是紅色的 -
and:
該謂詞表示此謂詞與另一個謂詞的短路邏輯AND,在計算組合謂詞時,如果此謂詞為假,則不計算其他謂詞,
Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150);-- > 蘋果又紅又重, -
or:
一個組合謂詞,該謂詞表示此謂詞與另一個謂詞的短路邏輯或,在計算組合謂詞時,如果此謂詞為真,則不計算其他謂詞,
Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getColor()));-- > 要么蘋果又紅又重,要么就是綠蘋果,
函式復合(Function)
compose()
andThen()
兩者都是函式的復合,其主要區別是:
- compose:
f.compose(g),先呼叫 g 再呼叫 f - andThen:
f.andThen(g),先呼叫 f 在呼叫 g
可以用作流水線模式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545026.html
標籤:其他
上一篇:【牛客】4 序列檢測&時序邏輯
