Java8 Stream reduce()


例子:
  怎樣用map和reduce方法數一數流中有多少個菜呢?
  答案:要解決這個問題,你可以把流中每個元素都映射成數字1,然后用reduce求和。這相當於按順序數流中的元素個數。

int count = menu.stream()
.map(d -> 1)
.reduce(0, (a, b) -> a + b);

  map和reduce的連接通常稱為map-reduce模式,因Google用它來進行網絡搜索而出名,因為它很容易並行化。同時,內置count方法也可用來計算流中元素的個數:

long count = menu.stream().count();
歸約方法的優勢與並行化
相比於前面寫的逐步迭代求和,使用reduce的好處在於,這里的迭代被內部迭代抽象掉了,這讓內部實現
得以選擇並行執行reduce操作。而迭代式求和例子要更新共享變量sum,這不是那么容易並行化的。如果你
加入了同步,很可能會發現線程競爭抵消了並行本應帶來的性能提升!這種計算的並行化需要另一種辦法:
將輸入分塊,分塊求和,最后再合並起來。但這樣的話代碼看起來就完全不一樣了。以后你會認識到使用
分支/合並框架來做是什么樣子。但現在重要的是要認識到,可變的累加器模式對於並行化來說是死路一條。
你需要一種新的模式,這正是reduce所提供的。使用流來對所有的元素並行求和時,你的代碼幾乎不用修改:
stream()換成了parallelStream()。
int sum = numbers.parallelStream().reduce(0, Integer::sum);
但要並行執行這段代碼也要付一定代價:傳遞給reduce的Lambda不能更改狀態(如實例變量),而且操作
必須滿足結合律才可以按任意順序執行。
流操作:無狀態和有狀態
	你已經看到了很多的流操作。乍一看流操作簡直是靈丹妙葯,而且只要在從集合生成流的時候把Stream
換成parallelStream就可以實現並行。當然,對於許多應用來說確實是這樣,就像前面的那些例子。你可以
把一張菜單變成流,用filter選出某一類的菜餚,然后對得到的流做map來對卡路里求和,最后reduce得到菜
單的總熱量。這個流計算甚至可以並行進行。但這些操作的特性並不相同。它們需要操作的內部狀態還是有些
問題的。
	諸如map或filter等操作會從輸入流中獲取每一個元素,並在輸出流中得到0或1個結果。這些操作一般
都是無狀態的:它們沒有內部狀態(假設用戶提供的Lambda或方法引用沒有內部可變狀態)。
但諸如reduce、sum、max等操作需要內部狀態來累積結果。在上面的情況下,內部狀態很小。在我們的例
子里就是一個int或double。不管流中有多少元素要處理,內部狀態都是有界的。
	相反,諸如sort或distinct等操作一開始都和filter和map差不多——都是接受一個流,再生成一個流
(中間操作),但有一個關鍵的區別。從流中排序和刪除重復項時都需要知道先前的歷史。例如,排序要求所有
元素都放入緩沖區后才能給輸出流加入一個項目,這一操作的存儲要求是無界的。要是流比較大或是無限的,
就可能會有問題(把質數流倒序會做什么呢?它應當返回最大的質數,但數學告訴我們它不存在)。我們
把這些操作叫作有狀態操作。
中間操作和終端操作
操作 類型 返回類型 使用的類型/函數式接口 函數描述符
filter 中間 Stream<T> Predicate<T> T -> boolean
distinct 中間(有狀態-無界) Stream<T>    
skip 中間(有狀態-有界) Stream<T> long  
limit 中間 Strem<T> long  
map 中間 Stream<R> Function<T,R> T -> R
flatMap 中間(有狀態-無界) Stream<R> Function<T,Stream<R>> T -> Stream<R>
sorted 終端 Stream<T> Comparator<T> (T, T) -> int
anyMatch 終端 boolean Predicate<T> T -> boolean
noneMatch 終端 boolean Predicate<T> T -> boolean
allMatch 終端 boolean Predicate<T> T -> boolean
findAny 終端 Optional<T>    
findFirst 終端 Optional<T>    
forEach 終端 void Consumer<T> T -> void
collect 終端 R Collector<T,A,R>  
reduce 終端(有狀態-有界) Optional<T> BinaryOperator<T> (T, T) -> T
count 終端 long    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM