Java 8 - Stream流骚操作解读2_归约操作
文章目錄
- Pre
- 什么是歸約操作
- 元素求和 reduce
- reduce如何運行的
- 最大值和最小值
Pre
Java 8 - Stream流騷操作解讀見到過的終端操作都是返回一個 boolean ( allMatch 之類的)、 void( forEach )或 Optional 對象( findAny 等)。也見過了使用 collect 來將流中的所有元素組合成一個 List 。
我們這里將學會如何把一個流中的元素組合起來,使用 reduce 操作來表達更復雜的查詢,比如“計算菜單中的總卡路里”或“菜單中卡路里最高的是哪一個”。
什么是歸約操作
此類查詢需要將流中所有元素反復結合起來,得到一個值,比如一個 Integer 。這樣的查詢可以被為歸約操作 (將流規約成一個值)
用函數式編程語言的術語來說,這稱為折疊(fold),因為你可以將這個操作看成把一張長長的紙(你的流)反復折疊成一個小方塊,而這就是規約操作的結果。
元素求和 reduce
在我們研究如何使用 reduce 方法之前,先來看看如何使用 for-each 循環來對數字列表中的元素求和
int sum = 0; for (int x : numbers) {sum += x; }numbers 中的每個元素都用加法運算符反復迭代來得到結果。通過反復使用加法,你把一個數字列表歸約成了一個數字。這段代碼中有兩個參數
- 總和變量的初始值,在這里是 0
- 將列表中所有元素結合在一起的操作,在這里是 + 。
要是還能把所有的數字相?,而不必去復制粘貼這段代碼,豈不是很好?這正是 reduce 操作的用武之地,它對這種重復應用的模式做了抽象。你可以像下面這樣對流中所有的元素求和:
int sum = numbers.stream().reduce(0, (a, b) -> a + b);reduce 接受兩個參數:
- 一個初始值,這里是0;
- 一個 BinaryOperator 來將兩個元素結合起來產生一個新值,這里我們用的是 lambda (a, b) -> a + b 。
你也很容易把所有的元素相?,只需要將另一個Lambda: (a, b) -> a * b 傳遞給 reduce操作就可以了
int product = numbers.stream().reduce(1, (a, b) -> a * b);我們把demo完善一下
public static void reduce(){List<Integer> list = Arrays.asList(11,2,3);int sum = list.stream().reduce(0, (a, b) ->a+b);System.out.println(sum);int cal = list.stream().reduce(1,(a, b) ->a*b);System.out.println(cal);}展示了 reduce 操作是如何作用于一個流的:Lambda反復結合每個元素,直到流被歸約層一個新的值。
reduce如何運行的
我們深入研究一下 reduce 操作是如何對一個數字流求和的。
- 首先, 0 作為Lambda( a )的第一個參數,從流中獲得 4 作為第二個參數( b ), 0 + 4 得到 4 ,它成了新的累積值。
- 然后再用累積值和流中下一個元素 5 調用Lambda,產生新的累積值 9 。
- 接下來,再用累積值和下一個元素 3調用Lambda,得到 12 。
- 最后,用 12 和流中最后一個元素 9 調用Lambda,得到最終結果 21
你可以使用方法引用讓這段代碼更簡潔。在Java 8中, Integer 類現在有了一個靜態的 sum方法來對兩個數求和,這?好是我們想要的,用不著反復用Lambda寫同一段代碼了:
public static void reduce(){List<Integer> list = Arrays.asList(11,2,3);int sum = list.stream().reduce(0,Integer::sum);System.out.println(sum);}【無初始值】
reduce 還有一個重載的變體,它不接受初始值,但是會返回一個 Optional 對象:
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));為什么它返回一個 Optional 呢?考慮流中沒有任何元素的情況。 reduce 操作無法返回其和,因為它沒有初始值。這就是為什么結果被包?在一個 Optional 對象里,以表明和可能不存在。
最大值和最小值
原來,只要用歸約就可以計算最大值和最小值了!讓我們來看看如何利用??學到的 reduce來計算流中最大或最小的元素。
reduce 接受兩個參數:
- 一個初始值
- 一個Lambda來把兩個流元素結合起來并產生一個新值
Lambda是一步步用加法運算符應用到流中每個元素上的, 。因此,你需要一個給定兩個元素能夠返回最大值的Lambda。 reduce 操作會考慮新值和流中下一個元素,并產生一個新的最大值,直到整個流消耗完
可以像下面這樣使用 reduce 來計算流中的最大值
Optional<Integer> max = numbers.stream().reduce(Integer::max);要計算最小值,你需要把 Integer.min 傳給 reduce 來替換 Integer.max :
Optional<Integer> min = numbers.stream().reduce(Integer::min);總結
以上是生活随笔為你收集整理的Java 8 - Stream流骚操作解读2_归约操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 8 - Stream流骚操作
- 下一篇: Java 8 - Stream实战