java 8 stream reduce詳解和誤區


java 8 stream reduce詳解和誤區

簡介

Stream API提供了一些預定義的reduce操作,比如count(), max(), min(), sum()等。如果我們需要自己寫reduce的邏輯,則可以使用reduce方法。

本文將會詳細分析一下reduce方法的使用,並給出具體的例子。

reduce詳解

Stream類中有三種reduce,分別接受1個參數,2個參數,和3個參數,首先來看一個參數的情況:

Optional<T> reduce(BinaryOperator<T> accumulator);

該方法接受一個BinaryOperator參數,BinaryOperator是一個@FunctionalInterface,需要實現方法:

R apply(T t, U u);

accumulator告訴reduce方法怎么去累計stream中的數據。

舉個例子:

List<Integer> intList = Arrays.asList(1,2,3);
        Optional<Integer> result1=intList.stream().reduce(Integer::sum);
        log.info("{}",result1);

上面的例子輸出結果:

com.flydean.ReduceUsage - Optional[6]

一個參數的例子很簡單。這里不再多說。

接下來我們再看一下兩個參數的例子:

T reduce(T identity, BinaryOperator<T> accumulator);

這個方法接收兩個參數:identity和accumulator。多出了一個參數identity。

也許在有些文章里面有人告訴你identity是reduce的初始化值,可以隨便指定,如下所示:

Integer result2=intList.stream().reduce(100, Integer::sum);
        log.info("{}",result2);

上面的例子,我們計算的值是106。

如果我們將stream改成parallelStream:

Integer result3=intList.parallelStream().reduce(100, Integer::sum);
        log.info("{}",result3);

得出的結果就是306。

為什么是306呢?因為在並行計算的時候,每個線程的初始累加值都是100,最后3個線程加出來的結果就是306。

並行計算和非並行計算的結果居然不一樣,這肯定不是JDK的問題,我們再看一下JDK中對identity的說明:

identity必須是accumulator函數的一個identity,也就是說必須滿足:對於所有的t,都必須滿足 accumulator.apply(identity, t) == t

所以這里我們傳入100是不對的,因為sum(100+1)!= 1。

這里sum方法的identity只能是0。

如果我們用0作為identity,則stream和parallelStream計算出的結果是一樣的。這就是identity的真正意圖。

下面再看一下三個參數的方法:

<U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);

和前面的方法不同的是,多了一個combiner,這個combiner用來合並多線程計算的結果。

同樣的,identity需要滿足combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

大家可能注意到了為什么accumulator的類型是BiFunction而combiner的類型是BinaryOperator?

public interface BinaryOperator<T> extends BiFunction<T,T,T>

BinaryOperator是BiFunction的子接口。BiFunction中定義了要實現的apply方法。

其實reduce底層方法的實現只用到了apply方法,並沒有用到接口中其他的方法,所以我猜測這里的不同只是為了簡單的區分。

總結

雖然reduce是一個很常用的方法,但是大家一定要遵循identity的規范,並不是所有的identity都是合適的。

本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/stream-reduce

歡迎關注我的公眾號:程序那些事,更多精彩等着您!
更多內容請訪問 www.flydean.com


免責聲明!

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



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