Java-Stream流式計算

什麼是 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 的並行迭代方式進行處理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章