什麼是 Stream流式計算
在 Java8 之前,如果我們想重新排序合併數據,一般是通過 for 循環或者 Iterator 迭代等方式進行操作。
但是這兩種方式通常在數據量比較大的情況下,效率比較低。
在Java8中,添加了一個新的接口Stream,可以通過 Lambda 表達式對集合進行各種非常便利、高效的聚合操作(Aggregate Operation),或者大批量數據操作 (Bulk Data Operation)。
Stream流式計算:將要處理的元素看做一種流,流在管道中傳輸,並且可以在管道的節點上處理,包括過濾篩選、去重、排序、聚合等,並把結果發送到下一計算節點。
舉例:對5個用戶進行篩選
- ID 必須是偶數
- 年齡必須大於23歲
- 用戶名轉爲大寫字母
- 用戶名字母倒着排序
- 只輸出一個用戶!
User類
class User {
int id, age;
String name;
public User() {}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
初始化的5個用戶
User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(6,"e",25);
使用傳統的方式來實現
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
List<String> nameList = new ArrayList<String>();
for (User u : list) {
if (u.getId() % 2 == 0)
if (u.getAge() > 23)
nameList.add(u.getName().toUpperCase());
}
nameList.sort(Comparator.reverseOrder());
System.out.println(nameList.get(0));
Stream進行實現
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
list.stream()
.filter(u -> {
return u.getId() % 2 == 0;
})
.filter(u -> {
return u.getAge() > 23;
})
.map(u -> {
return u.getName().toUpperCase();
})
.sorted((uu1, uu2) -> {
return uu2.compareTo(uu1);
})
.limit(1)
.forEach(System.out::println);
Stream 操作分類
Stream 的操作分爲兩大類:
-
中間操作(Intermediate operations)
- 只對操作進行了記錄,即只會返回一個流,不會進行計算操作
- 無狀態(Stateless):元素的處理不受之前元素的影響
- 有狀態(Stateful):只有拿到所有元素之後才能繼續下去
-
終結操作(Terminal operations)
- 終結操作是實現了計算操作
- 短路(Short-circuiting):遇到某些符合條件的元素就可以得到最終結果
- 非短路(Unshort-circuiting):必須處理完所有元素才能得到最終結果
串行處理和並行處理
-
串行處理操作:
- Stream 在執行每一步中間操作時,並不會做實際的數據操作處理,而是將這些中間操作串聯起來,生成一個數據處理鏈表,通過 Spliterator 迭代器進行數據處理。
- 每執行一次迭代,就對所有的無狀態的中間操作進行數據處理,而對有狀態的中間操作,就需要迭代處理完所有的數據,再進行處理操作
- 最後進行終結操作的數據處理。
-
並行處理操作(parallel()):
- Stream 對中間操作基本跟串行處理方式是一樣的
- 終結操作中,Stream 將結合ForkJoin對集合進行切片處理,ForkJoin 框架將每個切片的處理結果 Join 合併起來
建議
在循環迭代次數較少的情況下,常規的迭代方式性能其實更好,尤其是服務器CPU只有單核
服務器是多核 CPU 的情況下,Stream 的並行迭代優勢明顯。
所以在平時處理大數據的集合時,應該儘量考慮將應用部署在多核 CPU 環境下,並且使用 Stream 的並行迭代方式進行處理