Java8-Lambda表示式
Lambda表示式,它可以很簡潔地表示一個行為或傳遞程式碼,現在你可以把Lambda表示式看作匿名功能,它基本上就是沒有宣告名稱的方法,但和匿名類一樣,它也可以作為引數傳遞給一個方法
歡迎訪問本人部落格:http://wangnan.tech
Lambda管中窺豹
可以把lambda表示式理解為簡潔地表示可傳遞的匿名函式的一種方式:它沒有名稱,但它有引數列表,函式主體,返回型別,可能還有一個可以丟擲的異常列表
lambda表示式有三部分:
- 引數列表
- 箭頭
- lambda主體
有效的lambda表示式舉例:
(String s)->s.length()
這個lambda表示式具有一個string型別的引數,返回一個int,lambda沒有return語句,因為已經隱含了return
(Apple a)->a.getWeigh()>150
這個lambda表示式有一個Apple型別的引數並返回一個boolean
(int x,int y)->{
System.out.println("Result:");
System.out.println(x+y);
}
這個lambda表示式具有兩個int型別的引數,沒有返回值,注意lambda表示式可以包含多行語句
()->42
這個lambda表示式沒有引數,返回一個int
lambda表示式的基本語法是:
(parameters)-> expression
或:
(parameters)-> {expression}
下面哪個不是有效的lambda表示式?
()->{}
有效,lambda沒有引數,返回void
()->"Raoul"
有效,lambda沒有引數,返回string
()->{return "Mario";}
有效,lambda沒有引數,返回string,可以顯示的寫返回語句
(Integer i)->return "Alan"+i;
無效,需要使用花括號,如下:(Integer i)->{return "Alan"+i;}
(String s)->("IronMan";)
"IronMan"是一個表示式,不是一個語句,要使用此lambda有效,你可以去除花括號
或者,可以顯示的返回如下:(String s)->{return "IronMan"}
在哪裡以及如何使用Lamdda
可以在函式式介面上使用lambda
函式式介面
函式式介面就是指定義一個抽象方法的介面
比如:
public interface Predicate<T>{
boolean test (T t)
}
public interface Compartor<T>{
int compare(T o1,T o2);
}
public interface Runnable{
void run();
}
我們還知道,介面現在還可以擁有預設方法,哪怕有很多預設方法,只要介面只定義一個抽象方法,它就仍然是一個函式式介面
@FunctionalInterface
這個標註用於表示該介面會設計成一個函式式介面,如果你用了這個註解,而它卻不是一個函式式介面的話,編譯器將返回一個提示原因的錯誤
使用函式式介面
為了應用不同的lambda表示式,你需要一套能夠描述常見函式描述符的函式式介面
比如之間我們見過的Comparable Runnable Callable
Predicate
java.util.function.Predicate<T> 介面定義了一個名叫test的抽象方法,它接受泛型T物件,並返回一個boolean,在你需要一個涉及型別T的布林表示式時,就可以使用這個介面
consumer
java.util.funtion.Consumer<T> 定義了一個名叫accept的抽象方法,它接受泛型T的物件,沒有返回,你如果需要訪問型別T物件,並對其進行某些操作,可以使用這個介面
Function
java.util.funtion.Funtion<T,R>介面定義了一個叫作apply的方法,它接受一個泛型T的物件,並返回一個泛型R的物件,如果你需要定義一個lambda,將輸入物件的資訊對映到輸出,就可以使用這個介面
java8中常用的函式式介面
lambda及函式式介面的例子
型別檢查,型別推斷以及限制
型別檢查
lambda的型別時從使用拉門等到的上下文推斷出來的,比如,接受它傳遞的方法的引數,或接受它的值的區域性變數
lambda表示式型別檢查過程
使用區域性變數
lambda表示式允許使用自由變數(不是引數,而是在外層作用域中定義的變數)
例如:
int portNumber = 1337;
Runnable r = {}->System.out.println(portNumber)
儘管如此,有一些限制,lambda可以沒有限制地捕獲例項變數和靜態變數,但是區域性變數必須顯示宣告為final或事實上是final。換句話說,lambda表示式只能捕獲指派給他們的區域性變數一次
為什麼?
- 例項變數和區域性變數背後的實現有一個關鍵不同,例項變數儲存在堆中,而區域性變數保證在棧上,如果lambda可以訪問區域性變數,而且lambda是在一個執行緒中使用的,則是喲lambda執行緒可能會分配該變數的執行緒將這個變數回收之後,去訪問該變數。因此,java在訪問自由區域性變數時,實際上在是在訪問它的副本,而不是訪問原始變數,
- 這一限制不鼓勵你使用改變區域性變數的典型指令式程式設計模式,這種模式會阻礙並行處理
方法引用
方法引用讓你可以重複使用現有的方法定義,並像Lambda一樣傳遞他們,他們似乎更易讀,感覺也更自然
例如
先前:
inventory.sort((Apple a1,Apple a2)
->a1.getWeigh().compareTo(a2.getWeight()));
之後(使用方法引用和java.util.Comparator.comparing)
iventory.sort(comparting(Apple::getWeight));
方法應用可以被看作僅僅呼叫特定方法的lambda的一種快捷寫法,當你需要使用方法引用時,目標引用放在分隔符::前。方法的名稱放在後面,不需要括號,因為沒有實際呼叫這個方法
複合lambda表示式
你可以把多個簡單的lambda複合成複雜的表示式,比如兩個謂詞進行一個or操作,還可以讓一個函式的結果成為另一個函式的輸入
比如
逆序
inventory.sort(comparing(Apple::getWeight).reversed())
比較器鏈
inventory.sort(comparing(Apple::getWeight)
.reversed()
.thenComparing(Apple:getCountry()));
謂詞複合
三個方法:negate() and() or()
函式複合
andThen() 意味著g(f(x))
compose() 意味著f(g(x))
小結
- lambda表示式可以理解為一種匿名函式
- 函式式介面就是僅僅宣告瞭一個抽象方法的介面
- 只有在接受函式式介面的地方才可以使用Lambda表示式
- java8自帶了一些常用的函式式介面,放在java.util.function包裡
- 方法引用讓你重複使用現有的方法並直接傳遞他們
(注:內容整理自《Java8實戰》)
歡迎關注我的微信訂閱號
歡迎關注我的開發者頭條獨家號搜尋:269166
相關文章
- 表示式
- 中綴表示式轉字尾表示式
- JavaScript 表示式JavaScript
- Cron 表示式
- cron表示式
- lambda 表示式
- lambda表示式
- el 表示式
- 表示式樹
- 中綴表示式轉為逆波蘭表示式
- javascript-函式表示式JavaScript函式
- 函式表示式–遞迴函式遞迴
- “正規表示式”應當稱為“規則表示式”
- 正規表示式
- Java | Lambda表示式Java
- JavaScript短路表示式JavaScript
- 尤達表示式
- 【Kotlin】Lambda表示式Kotlin
- 三目表示式
- 正規表示式.
- CPP lambda表示式
- shell正在表示式
- 八,Lambda表示式
- 中綴表示式
- Python Lambda 表示式Python
- 3.2.5 表示式求值
- Lambda表示式(Java)Java
- Java Lambda表示式Java
- Python - lambda 表示式Python
- kotlin lambda表示式Kotlin
- SQL CASE 表示式SQL
- matlab表示函式Matlab函式
- SpEL表示式注入
- 中綴表示式轉化為字尾表示式並求值
- 關於利用STL棧求解四則中綴表示式以及中綴表示式轉逆波蘭表示式和逆波蘭表示式的求解
- kotlin 函式和 Lambda 表示式Kotlin函式
- 【正規表示式】常用的正規表示式(數字,漢字,字串,金額等的正規表示式)字串
- C# Lambda表示式詳解,及Lambda表示式樹的建立C#