前言
Java 8 (又稱為 jdk 1.8) 是 Java 語言開發的一個主要版本。 Oracle 公司於 2014 年 3 月 18 日發布 Java 8 ,它支持函數式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
簡介
Java8 新增了非常多的特性,主要關注以下幾個(摘自官網,機翻):
-
-
Lambda Expressions是一種新的語言功能,已在此版本中引入。它們使您可以將功能視為方法參數,或將代碼視為數據。Lambda表達式允許您更緊湊地表示單方法接口(稱為功能接口)的實例。
-
方法引用為已經具有名稱的方法提供易於閱讀的lambda表達式。
-
默認方法允許將新功能添加到庫的接口,並確保與為這些接口的舊版本編寫的代碼的二進制兼容性。
-
重復注釋提供了對同一聲明或類型使用多次應用相同注釋類型的功能。
-
類型注釋提供了在使用類型的任何地方應用注釋的功能,而不僅僅是在聲明上。與可插拔類型系統一起使用時,此功能可以改進代碼的類型檢查。
-
改進的類型推斷。
-
方法參數反射。
-
-
-
新
java.util.stream包中的類提供Stream API以支持對元素流的功能樣式操作。Stream API集成到Collections API中,可以對集合進行批量操作,例如順序或並行map-reduce轉換。 -
具有hash沖突的HashMaps的性能改進
-
-
-
默認情況下啟用客戶端TLS 1.2
-
更強大的基於密碼加密的算法
-
SHA-224消息摘要
-
-
-
Unicode增強功能,包括對Unicode 6.2.0的支持
-
采用Unicode CLDR數據和java.locale.providers系統屬性
-
新日歷和區域設置API
-
能夠將自定義資源包安裝為擴展
-
-
日期時間包 - 一組新的包,提供全面的日期時間模型。
-
-
減小
<JDK_HOME>/jre/lib/charsets.jar文件的大小 -
java.lang.String(byte[], *)構造函數和java.lang.String.getBytes()方法的性能改進。
-
-
-
並行陣列排序
-
標准編碼和解碼Base64
-
無符號算術支持
-
-
-
類和接口已添加到
java.util.concurrent包中。 -
已將
java.util.concurrent.ConcurrentHashMap類添加到類中以支持基於新添加的流工具和lambda表達式的聚合操作。 -
已將類添加到
java.util.concurrent.atomic包中以支持可伸縮的可更新變量。 -
方法已添加到
java.util.concurrent.ForkJoinPool類中以支持公共池。 -
該
java.util.concurrent.locks.StampedLock班已添加到提供基於能力的鎖有三種模式控制讀/寫訪問。
-
-
-
去除PermGen。
-
本文主要圍繞以下幾點進行介紹
-
Lambda 表達式 − Lambda允許把函數作為一個方法的參數(函數作為參數傳遞進方法中)
-
方法引用 − 方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗余代碼。
-
默認方法 − 默認方法就是一個在接口里面有了一個實現的方法。
-
Stream API −新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。
-
Date Time API − 加強對日期與時間的處理。
-
Optional 類 − Optional 類已經成為 Java 8 類庫的一部分,用來解決空指針異常。
- HashMap改進
Lambda表達式
Lambda 表達式,也可稱為閉包,它是推動 Java 8 發布的最重要新特性。
Lambda表達式有兩個特點:一是匿名函數,二是可傳遞。
匿名函數的應用場景是:
通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用Lambda表達式。lambda表達式所表示的匿名函數的內容應該是很簡單的,如果復雜的話,干脆就重新定義一個函數了,使用lambda就有點過於執拗了。
可傳遞使用場景是:
就是將Lambda表達式傳遞給其他的函數,它當做參數,Lambda作為一種更緊湊的代碼風格,使Java的語言表達能力得到提升。
語法
(parameters) ->{ statements; }
Lambda表達式在Java語言中引入了一個新的語法元素和操作符。這個操作符為"->",該操作符被稱為Lambda操作符或箭頭操作符,它將Lambda分為兩個部分:
左側:指定了Lambda表達式所需要的所有參數
右側:指定了Lambda體,即Lambda表達式所要執行的功能。
- 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
- 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
- 可選的大括號:如果主體只有一個語句,就可以不需要使用大括號。
- 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。
舉個🌰:
// 1. 不需要參數,返回值為 5 () -> 5 // 2. 接收一個參數(數字類型),返回其2倍的值 x -> 2 * x // 3. 接受2個參數(數字),並返回他們的差值 (x, y) -> x – y // 4. 接收2個int型整數,返回他們的和 (int x, int y) -> x + y // 5. 接受一個 string 對象,並在控制台打印,不返回任何值(看起來像是返回void) (String s) -> System.out.print(s) //6. 接收2個參數(數字),並返回他們相除的結果 (x,y) -> { if(x<0){ return 0; } return y/x; }
接下來是個完整的例子:
public class Java8Tester { public static void main(String args[]){ Java8Tester tester = new Java8Tester(); // 類型聲明 MathOperation addition = (int a, int b) -> a + b; // 不用類型聲明 MathOperation subtraction = (a, b) -> a - b; // 大括號中的返回語句 MathOperation multiplication = (int a, int b) -> { return a * b; }; // 沒有大括號及返回語句 MathOperation division = (int a, int b) -> a / b; System.out.println("10 + 5 = " + tester.operate(10, 5, addition)); System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction)); System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication)); System.out.println("10 / 5 = " + tester.operate(10, 5, division)); // 不用括號 GreetingService greetService1 = message -> System.out.println("Hello " + message); // 用括號 GreetingService greetService2 = (message) -> System.out.println("Hello " + message); greetService1.sayMessage("Runoob"); greetService2.sayMessage("Google"); } interface MathOperation { int operation(int a, int b); } interface GreetingService { void sayMessage(String message); } private int operate(int a, int b, MathOperation mathOperation){ return mathOperation.operation(a, b); } }
使用 Lambda 表達式需要注意以下兩點:
- Lambda 表達式主要用來定義行內執行的方法類型接口,例如,一個簡單方法接口。在上面例子中,我們使用各種類型的Lambda表達式來定義MathOperation接口的方法。然后我們定義了sayMessage的執行。
- 使用lambda表達式實現接口僅適用於該接口有且只有一個抽象方法
- Lambda 表達式免去了使用匿名方法的麻煩,並且給予Java簡單但是強大的函數化的編程能力。
變量作用域
lambda 表達式只能引用標記了 final 的外層局部變量,這就是說不能在 lambda 內部修改定義在域外的局部變量,否則會編譯錯誤。
舉個🌰:
public class Java8Tester { public static void main(String args[]) { int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); // 輸出結果為 3 //接下來如果改變num的值會報錯,因為num傳入lambda表達式即其隱性的具有final語義 //num = 2; } public interface Converter<T1, T2> { void convert(int i); } }
再舉個java8前后使用lambda語法差異的🌰
public class Test { public static void main(String[] args) { // Java8之前: new Thread(new Runnable() { public void run() { System.out.println("hello world"); } }).start(); // Java8方式: new Thread(() -> System.out.println("hello world")).start(); } }
常用例子
//list轉set
List<Tags> list = new ArrayList<>(); Set<Integer> tagIdSet = list.stream().map(Tags::getTagId).collect(Collectors.toSet());
//list轉map
List<Tags> crowdHitList = new ArrayList<>();
Map<String,Long> resultMap = crowdHitList.stream().collect(Collectors.toMap(Tags::getCrowdId, tag-> {
if (tag.getTotal() == null) {
return 0L;
} else {
return tag.getTotal();
}
}));
參考地址:https://www.runoob.com/java/java8-lambda-expressions.html
