Java8 新增了非常多的特性,我們主要討論以下幾個:
- Lambda 表達式 − Lambda允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中。
- 方法引用 − 方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘代碼。
- 默認方法 − 默認方法就是一個在接口裏面有了一個實現的方法。
- 新工具 − 新的編譯工具,如:Nashorn引擎 jjs、 類依賴分析器jdeps。
- Stream API −新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。
- Date Time API − 加強對日期與時間的處理。
- Optional 類 − Optional 類已經成爲 Java 8 類庫的一部分,用來解決空指針異常。
- Nashorn, JavaScript 引擎 − Java 8提供了一個新的Nashorn javascript引擎,它允許我們在JVM上運行特定的javascript應用。
1. Lambda 表達式實例
1.1. 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)
1.2.使用注意事項
- lambda 表達式只能引用標記了 final 的外層局部變量,這就是說不能在 lambda 內部修改定義在域外的局部變量,否則會編譯錯誤。
- 在 Lambda 表達式當中不允許聲明一個與局部變量同名的參數或者局部變量。
2. 方法引用
方法引用通過方法的名字來指向一個方法。
方法引用可以使語言的構造更緊湊簡潔,減少冗餘代碼。
方法引用使用一對冒號 :: 。
names.forEach(System.out::println);
3. 函數式接口
函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。
函數式接口可以被隱式轉換爲 lambda 表達式。
Lambda 表達式和方法引用(實際上也可認爲是Lambda表達式)上。
JDK 1.8 新增加的函數接口:
- java.util.function
java.util.function 它包含了很多類,用來支持 Java的 函數式編程。
4. 默認方法
簡單說,默認方法就是接口可以有實現方法,而且不需要實現類去實現其方法。
我們只需在方法名前面加個 default 關鍵字即可實現默認方法。
5. Stream
Stream 使用一種類似用 SQL 語句從數據庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。
這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。
元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。
Stream(流)是一個來自數據源的元素隊列並支持聚合操作。
5.1. Stream操作還有兩個基礎的特徵:
- Pipelining: 中間操作都會返回流對象本身。 這樣多個操作可以串聯成一個管道, 如同流式風格(fluent style)。 這樣做可以對操作進行優化, 比如延遲執行(laziness)和短路( short-circuiting)。
- 內部迭代: 以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進行迭代, 這叫做外部迭代。 Stream提供了內部迭代的方式, 通過訪問者模式(Visitor)實現。
5.2. 在 Java 8 中, 集合接口有兩個方法來生成流:
- stream() − 爲集合創建串行流。
- parallelStream() − 爲集合創建並行流。
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
//parallelStream 是流並行處理程序的代替方法。以下我們使用 parallelStream 來輸出空字符串的數量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 獲取空字符串的數量 int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
5.3. 聚合操作
5.3.1. forEach
Stream 提供了新的方法 'forEach' 來迭代流中的每個數據。以下代碼使用 forEach 輸出了10個隨機數:
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
5.3.2. map
map 方法用於映射每個元素到對應的結果,以下代碼片段使用 map 輸出了元素對應的平方數:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); // 獲取對應的平方數 List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
5.3.3. filter
filter 方法用於通過設置的條件過濾出元素。以下代碼片段使用 filter 方法過濾出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 獲取空字符串的數量 int count = strings.stream().filter(string -> string.isEmpty()).count();
5.3.4. limit
limit 方法用於獲取指定數量的流。 以下代碼片段使用 limit 方法打印出 10 條數據:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
5.3.5. sorted
sorted 方法用於對流進行排序。以下代碼片段使用 sorted 方法對輸出的 10 個隨機數進行排序:
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
5.3.6. Collectors
Collectors 類實現很多歸約操作,如將流轉換成集合和聚合元素。Collectors 可用於返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("篩選列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合併字符串: " + mergedString);
6. Optional 類
Optional 類是一個可以爲null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象。
Optional 是個容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。
Optional 類的引入很好的解決空指針異常。
7.日期時間 API
Java 8 在 java.time 包下提供了很多新的 API。以下爲兩個比較重要的 API:
- Local(本地) − 簡化了日期時間的處理,沒有時區的問題。
- Zoned(時區) − 通過制定的時區處理日期時間。
新的java.time包涵蓋了所有處理日期,時間,日期/時間,時區,時刻(instants),過程(during)與時鐘(clock)的操作。
8. Base64
Java 8 內置了 Base64 編碼的編碼器和解碼器。
Base64工具類提供了一套靜態方法獲取下面三種BASE64編解碼器:
- 基本:輸出被映射到一組字符A-Za-z0-9+/,編碼不添加任何行標,輸出的解碼僅支持A-Za-z0-9+/。
- URL:輸出映射到一組字符A-Za-z0-9+_,輸出是URL和文件。
- MIME:輸出隱射到MIME友好格式。輸出每行不超過76字符,並且使用'\r'並跟隨'\n'作爲分割。編碼輸出最後沒有行分割。