Java自問世以來,已經經過了數次升級,這里
北大青鳥深圳嘉華學校將介紹Java8的新特性之一——Lambda 表達式,希望這點
Java開發教程知識能對Java開發者們有所幫助。
首先我們了解一下lambda表達式是什么?
說起lambda表達式,第一個需要說明的就是它是Java8的幾個重量級新特性之一,它能使Java程序設計更加簡潔。在這篇文章里,我們將通過探討lambda表達式、依托于函數式接口使用lambda表達式等知識,詳細介紹Java8 新特性Lambda 表達式。
關于lambda表達式定義
我們可以將lambda表達式定義為一種 簡潔、可傳遞的匿名函數,首先我們需要明確lambda表達式本質上是一個函數,雖然它不屬于某個特定的類,但具備參數列表、函數主體、返回類型,以及能夠拋出異常;其次它是匿名的,lambda表達式沒有具體的函數名稱;lambda表達式可以像參數一樣進行傳遞,從而極大的簡化代碼的編寫。格式定義如下:
格式一: 參數列表 -> 表達式
格式二: 參數列表 -> {表達式集合}
需要注意的是,lambda表達式隱含了return關鍵字,所以在單個的表達式中,我們無需顯式的寫return關鍵字,但是當表達式是一個語句集合的時候,則需要顯式添加return,并用花括號{ }將多個表達式包圍起來,下面看幾個例子:
依托于函數式接口使用lambda表達式
lambda表達式的使用需要借助于函數式接口,也就是說只有函數式接口出現地方,我們才可以將其用lambda表達式進行簡化。
自定義函數式接口
函數式接口定義為只具備 一個抽象方法 的接口。
java8在接口定義上的改進就是引入了默認方法,使得我們可以在接口中對方法提供默認的實現,但是不管存在多少個默認方法,只要具備一個且只有一個抽象方法,那么它就是函數式接口,如下(引用上面的AppleFilter):
AppleFilter僅包含一個抽象方法accept(Apple apple),依照定義可以將其視為一個函數式接口,在定義時我們為該接口添加了@FunctionalInterface注解,用于標記該接口是函數式接口,不過這個接口是可選的,當添加了該接口之后,編譯器就限制了該接口只允許有一個抽象方法,否則報錯,所以推薦為函數式接口添加該注解。
jdk自帶的函數式接口
jdk為lambda表達式已經內置了豐富的函數式接口,如下表所示(僅列出部分):
下面分別就Predicate<T>、Consumer<T>、Function<T, R>的使用示例說明。
Predicate<T>
Predicate的功能類似于上面的AppleFilter,利用我們在外部設定的條件對于傳入的參數進行校驗,并返回驗證結果boolean,下面利用Predicate對List集合的元素進行過濾:
利用上面的函數式接口過濾字符串集合中的空字符串:
demo.filter(list, (String str) -> null != str && !str.isEmpty());
Consumer<T>
Consumer提供了一個accept抽象函數,該函數接收參數,但不返回值,下面利用Consumer遍歷集合:
利用上面的函數式接口,遍歷字符串集合,并打印非空字符串:
Function<T, R>
Funcation執行轉換操作,輸入是類型T的數據,返回R類型的數據,下面利用Function對集合進行轉換:
下面利用上面的函數式接口,將一個封裝字符串(整型數字的字符串表示)的接口,轉換成整型集合:
demo.filter(list, (String str) -> Integer.parseInt(str));
上面這些函數式接口還提供了一些邏輯操作的默認實現,留到后面介紹java8接口的默認方法時再講吧~
使用過程中需要注意的一些事情
類型推斷
在編碼過程中,有時候可能會疑惑我們的調用代碼會去具體匹配哪個函數式接口,實際上編譯器會根據參數、返回類型、異常類型(如果存在)等做正確的判定。
在具體調用時,在一些時候可以省略參數的類型,從而進一步簡化代碼:
局部變量
上面所有例子我們的lambda表達式都是使用其主體參數,我們也可以在lambda中使用局部變量,如下:
該例子中我們在lambda中使用了局部變量weight,不過在lambda中使用局部變量必須要求該變量 顯式聲明為final或事實上的final ,這主要是因為局部變量存儲在棧上,lambda表達式則在另一個線程中運行,當該線程視圖訪問該局部變量的時候,該變量存在被更改或回收的可能性,所以用final修飾之后就不會存在線程安全的問題。