官术网_书友最值得收藏!

1.12 約簡操作

reduce方法是一種用于從流中計算某個值的通用機制,其最簡單的形式將接受一個二元函數,并從前兩個元素開始持續應用它。如果該函數是求和函數,那么就很容易解釋這種機制:

在上面的情況中,reduce方法會計算v0+v1+v2+…,其中vi是流中的元素。如果流為空,那么該方法會返回一個Optional,因為沒有任何有效的結果。

注意:在上面的情況中,可以寫成reduce(Integer::sum)而不是reduce((x,y)->x+y)。

通常,如果reduce方法有一項約簡操作op,那么該約簡就會產生v0 op v1 op v2 op…,其中我們將函數調用op(vi,vi+1)寫作vi op vi+1。這項操作應該是可結合的:即組合元素時使用的順序不應該成為問題。在數學標記法中,(x op y)op z必須等于x op(y op z)。這使得在使用并行流時,可以執行高效的約簡。

有很多種在實踐中會顯得很有用的可結合操作,例如求和、乘積、字符串連接、取最大值和最小值、求集的并與交等。減法是一個不可結合操作的例子,例如,(6-3)-2≠6-(3-2)。

通常,會有一個幺元值e使得e op x=x,可以使用這個元素作為計算的起點。例如,0是加法的幺元值。然后,可以調用第2種形式的reduce:

如果流為空,則會返回幺元值,你就再也不需要處理Optional類了。

現在,假設你有一個對象流,并且想要對某些屬性求和,例如字符串流中的所有字符串的長度,那么你就不能使用簡單形式的reduce,而是需要(T,T)->T這樣的函數,即引元和結果的類型相同的函數。但是在這種情況下,你有兩種類型:流的元素具有String類型,而累積結果是整數。有一種形式的reduce可以處理這種情況。

首先,你需要提供一種“累積器”函數(total,word)->total+word.length()。這個函數會被反復調用,產生累積的總和。但是,當計算被并行化時,會有多個這種類型的計算,你需要將它們的結果合并。因此,你需要提供第二個函數來執行此處理。完整的調用如下:

注意:在實踐中,你可能并不會頻繁地用到reduce方法。通常,映射為數字流并使用其方法來計算總和、最大值和最小值會更容易。(我們將在1.13節中討論數字流。)在這個特定示例中,你可以調用words.mapToInt(String::length).sum(),因為它不涉及裝箱操作,所以更簡單也更高效。

注意:有時reduce會顯得并不夠通用。例如,假設我們想要收集BitSet中的結果。如果收集操作是并行的,那么就不能直接將元素放到單個BitSet中,因為BitSet對象不是線程安全的。因此,我們不能使用reduce,因為每個部分都需要以其自己的空集開始,并且reduce只能讓我們提供一個幺元值。此時,應該使用collect,它會接受單個引元:

1.一個提供者,它會創建目標類型的新實例,例如散列集的構造器。

2.一個累積器,它會將一個元素添加到一個實例上,例如add方法。

3.一個組合器,它會將兩個實例合并成一個,例如addAll。

下面的代碼展示了collect方法是如何操作位集的:

java.util.Stream 8

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

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

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

用給定的accumulator函數產生流中元素的累積總和。如果提供了幺元,那么第一個被累計的元素就是該幺元。如果提供了組合器,那么它可以用來將分別累積的各個部分整合成總和。

·<R>Rcollect(Supplier<R>supplier,BiConsumer<R,?superT>

將元素收集到類型R的結果中。在每個部分上,都會調用supplier來提供初始結果,調用accumulator來交替地將元素添加到結果中,并調用combiner來整合兩個結果。

主站蜘蛛池模板: 北京市| 郑州市| 富阳市| 齐河县| 阳新县| 吉首市| 思南县| 八宿县| 临高县| 雷波县| 甘孜县| 汶川县| 祁东县| 闽侯县| 永济市| 杭锦旗| 财经| 游戏| 璧山县| 南康市| 西乌珠穆沁旗| 长子县| 闽侯县| 邵武市| 四子王旗| 岳池县| 灌南县| 屯门区| 深圳市| 抚宁县| 新邵县| 高清| 洮南市| 叙永县| 克拉玛依市| 天峨县| 科技| 泰来县| 文安县| 响水县| 句容市|