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