
Stream API為我們提供了`Stream.reduce`用來實現集合元素的歸約。reduce函數有三個參數:
* *Identity標識*:一個元素,它是歸約操作的初始值,如果流為空,則為默認結果。
* *Accumulator累加器*:具有兩個參數的函數:歸約運算的部分結果和流的下一個元素。
* *Combiner合并器(可選)*:當歸約并行化時,或當累加器參數的類型與累加器實現的類型不匹配時,用于合并歸約操作的部分結果的函數。

注意觀察上面的圖,我們先來理解累加器:
* 階段累加結果作為累加器的第一個參數
* 集合遍歷元素作為累加器的第二個參數
## Integer類型歸約
reduce初始值為0,累加器可以是lambda表達式,也可以是方法引用。
~~~
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers
.stream()
.reduce(0, (subtotal, element) -> subtotal + element);
System.out.println(result); //21
int result = numbers
.stream()
.reduce(0, Integer::sum);
System.out.println(result); //21
~~~
## String類型歸約
不僅可以歸約Integer類型,只要累加器參數類型能夠匹配,可以對任何類型的集合進行歸約計算。
~~~
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters
.stream()
.reduce("", (partialString, element) -> partialString + element);
System.out.println(result); //abcde
String result = letters
.stream()
.reduce("", String::concat);
System.out.println(result); //ancde
~~~
## 復雜對象歸約
計算所有的員工的年齡總和。
~~~
Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
Employee e2 = new Employee(2,13,"F","Martina","Hengis");
Employee e3 = new Employee(3,43,"M","Ricky","Martin");
Employee e4 = new Employee(4,26,"M","Jon","Lowman");
Employee e5 = new Employee(5,19,"F","Cristine","Maria");
Employee e6 = new Employee(6,15,"M","David","Feezor");
Employee e7 = new Employee(7,68,"F","Melissa","Roy");
Employee e8 = new Employee(8,79,"M","Alex","Gussin");
Employee e9 = new Employee(9,15,"F","Neetu","Singh");
Employee e10 = new Employee(10,45,"M","Naveen","Jain");
List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
Integer total = employees.stream().map(Employee::getAge).reduce(0,Integer::sum);
System.out.println(total); //346
~~~
* 先用map將Stream流中的元素由Employee類型處理為Integer類型(age)。
* 然后對Stream流中的Integer類型進行歸約
## Combiner合并器的使用
除了使用map函數實現類型轉換后的集合歸約,我們還可以用Combiner合并器來實現,這里第一次使用到了Combiner合并器。
因為Stream流中的元素是Employee,累加器的返回值是Integer,所以二者的類型不匹配。這種情況下可以使用Combiner合并器對累加器的結果進行二次歸約,相當于做了類型轉換。
~~~
Integer total3 = employees.stream()
.reduce(0,(totalAge,emp) -> totalAge + emp.getAge(),Integer::sum); //注意這里reduce方法有三個參數
System.out.println(total); //346
~~~
計算結果和使用map進行數據類型轉換的方式是一樣的。
## 并行流數據歸約(使用合并器)
對于大數據量的集合元素歸約計算,更能體現出Stream并行流計算的威力。

在進行并行流計算的時候,可能會將集合元素分成多個組計算。為了更快的將分組計算結果累加,可以使用合并器。
~~~
Integer total2 = employees
.parallelStream()
.map(Employee::getAge)
.reduce(0,Integer::sum,Integer::sum); //注意這里reduce方法有三個參數
System.out.println(total); //346
~~~
- 前言
- 1.lambda表達式會用了么
- 2.初識Stream-API
- 3.Stream的filter與謂語邏輯
- 4.Stream管道流的map操作
- 5.Stream的狀態與并行操作
- 6.Stream性能差?不要人云亦云
- 7.像使用SQL一樣排序集合
- 8.函數式接口Comparator
- 9.Stream查找與匹配元素
- 10.Stream集合元素歸約
- 11.StreamAPI終端操作
- 12.java8如何排序Map
- Stream流逐行文件處理
- java8-forEach(持續發布中)
- 筆者其它作品推薦
- vue深入淺出系列
- 手摸手教你學Spring Boot2.0
- Spring Security-JWT-OAuth2一本通
- 實戰前后端分離RBAC權限管理系統
- 實戰SpringCloud微服務從青銅到王者