java stream操作
Java 8 中的 Streams API 詳解
Streams 的背景,以及 Java 8 中的使用詳解
陳 爭雲, 佔 宇劍, 和 司 磊2014 年 9 月 11 日釋出 16
為什麼需要 Stream
Stream 作為 Java 8 的一大亮點,它與 java.io 包裡的 InputStream 和 OutputStream 是完全不同的概念。它也不同於 StAX 對 XML 解析的 Stream,也不是 Amazon Kinesis 對大資料實時處理的 Stream。Java 8 中的 Stream 是對集合(Collection)物件功能的增強,它專注於對集合物件進行各種非常便利、高效的聚合操作(aggregate operation),或者大批量資料操作 (bulk data operation)。Stream API 藉助於同樣新出現的 Lambda 表示式,極大的提高程式設計效率和程式可讀性。同時它提供序列和並行兩種模式進行匯聚操作,併發模式能夠充分利用多核處理器的優勢,使用 fork/join 並行方式來拆分任務和加速處理過程。通常編寫並行程式碼很難而且容易出錯, 但使用 Stream API 無需編寫一行多執行緒的程式碼,就可以很方便地寫出高效能的併發程式。所以說,Java 8 中首次出現的 java.util.stream 是一個函式式語言+多核時代綜合影響的產物。
什麼是聚合操作
在傳統的 J2EE 應用中,Java 程式碼經常不得不依賴於關係型資料庫的聚合操作來完成諸如:
- 客戶每月平均消費金額
- 最昂貴的在售商品
- 本週完成的有效訂單(排除了無效的)
- 取十個資料樣本作為首頁推薦
這類的操作。
但在當今這個資料大爆炸的時代,在資料來源多樣化、資料海量化的今天,很多時候不得不脫離 RDBMS,或者以底層返回的資料為基礎進行更上層的資料統計。而 Java 的集合 API 中,僅僅有極少量的輔助型方法,更多的時候是程式設計師需要用 Iterator 來遍歷集合,完成相關的聚合應用邏輯。這是一種遠不夠高效、笨拙的方法。在 Java 7 中,如果要發現 type 為 grocery 的所有交易,然後返回以交易值降序排序好的交易 ID 集合,我們需要這樣寫:
清單 1. Java 7 的排序、取值實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
List<
Transaction
> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
if(t.getType() == Transaction.GROCERY){
groceryTransactions.add(t);
}
}
Collections.sort(groceryTransactions, new Comparator(){
public int compare(Transaction t1, Transaction t2){
return t2.getValue().compareTo(t1.getValue());
}
});
List<
Integer
> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
transactionsIds.add(t.getId());
}
|
而在 Java 8 使用 Stream,程式碼更加簡潔易讀;而且使用併發模式,程式執行速度更快。
清單 2. Java 8 的排序、取值實現
1 2 3 4 5 |
List<
Integer
> transactionsIds = transactions.parallelStream().
filter(t -> t.getType() == Transaction.GROCERY).
sorted(comparing(Transaction::getValue).reversed()).
map(Transaction::getId).
collect(toList());
|
Stream 總覽
什麼是流
Stream 不是集合元素,它