Java8之Stream流(三)縮減操作
Java8之Stream流(一)基礎體驗
Java8之Stream流(二)關鍵知識點
Java8之Stream流(四)並行流
Java8之Stream流(五)對映流
Java8之Stream流(六)收集
Java8之Stream流(七)流與迭代器
和前面兩篇文章一起服用,效果會更佳。通過對流API的基礎體驗Demo和關鍵知識點的講解 ,相信大家對流API都有一定的認識了,但是流API強大的功能,可不僅僅像前面兩篇文章中說的那樣簡單,大家應該注意到,在第二篇中,我對Stream介面進行介紹的時候,並沒有把他的全部方法都進行了解析說明。沒錯,從這一篇開始,那些還沒有講解的方法,很可能就開始變成我們的主角了,大家從題目上面應該知道了,本期我們要講的是流API的縮減操作。
何為縮減操作?
我們先考慮一下min()和max(),這兩個方法我們在第一篇和第二篇中均有提到,其中min()是返回流中的最小值,而max()返回流中最大值,前提是他們存在。他們之間的特點是什麼?①都返回了一個值②由一可知,他們是終端操作。如果我們用流API的術語來形容前面這兩種特性的結合體的話,它們代表了縮減操作。因為每個縮減操作都把一個流縮減為一個值,好比最大值,最小值。當然流API,把min()和max(),count()這些操作稱為特例縮減。即然說到了特例,肯定就有泛化這種概念了,他就是reduce()方法了,其實第二篇當中,他已經出現過了,只是當時我沒有去強調他。
public interface Stream<T> extends BaseStream<T, Stream<T>> {
//、、、忽略其他無關緊要的元素
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
}
Stream介面定義了三個版本的reduce(),我們先使用前面兩個,
T reduce(T identity, BinaryOperator<T> accumulator);//1
Optional<T> reduce(BinaryOperator<T> accumulator);//2
第一個版本返回的是一個T型別的物件,T代表的是流中的元素型別!第二個版本是返回一個Optional型別物件。對於這兩種形式,accumulator是一個操作兩個值並得到結果的函式。在第一個版本當中,identity是這樣一個值,對於涉及identity和流中任意的累積操作,得到的結果就是元素自身,沒有任何改變。比如,如果是加法,他就是0,如果是乘法他就是1。
其中的accumulator是一個BinaryOperator<T>的型別,他是java.util.function包中宣告的函式式介面,它擴充套件了BiFunction函式式介面.
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
}
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);//notice
}
BiFunction介面中的apply()方法的原型在//notice
。其中R指定了結果的型別,T,U分別是第一引數的型別和第二個引數的型別,因此apply()對他的兩個運算元(t,u)應用到同一個函式上,並返回結果,而對BinaryOperator<T>來說,他在擴充套件 BiFunction時,指定了所有的型別引數都是相同的T,因此對於BinaryOperator<T>函式式介面的apply來說,他也就變成了 T apply(T t, T u),此外,還有一個需要注意的地方是,在應用reduce()時,apply()的第一個引數t,包含的是一個結果,u包含的是下一個元素。在第一次呼叫時,將取決於使用reduce()的版本,t可能是單位值,或者是前一個元素。
縮減操作的三個約束
- 無狀態
- 不干預
- 關聯性
無狀態,這裡可不是LOL的那個無狀態,畢竟他退役了。相信讀過第二篇文章的同學已經很容易理解了,簡單來說無狀態就是每個元素都被單獨地處理,他和流中的其它元素是沒有任何依賴關係的。不干預是指運算元不會改變資料來源。最後,操作必須具有關聯性,這裡的關聯性是指標準的數學含義,即,給定一個關聯運算子,在一系列操作中使用該運算子,先處理哪一對運算元是無關緊要的。比如,(1 * 2) * 3 <===> 1 * (2 * 3)。其中關聯性,在並行流中,是至關重要的。
下面我用一個簡單的例子帶著大家實戰一下泛化縮減操作reduce()的使用。
public class Main {
public static void main(String[] args) {
learnStream();
}
private static void learnStream() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(5);
lists.add(6);
Optional<Integer> sum = lists.stream().reduce((a, b) -> a + b);
if (sum.isPresent()) System.out.println("list的總和為:" + sum.get());//21
//<====> lists.stream().reduce((a, b) -> a + b).ifPresent(System.out::println);
Integer sum2 = lists.stream().reduce(0, (a, b) -> a + b);//21
System.out.println("list的總和為:" + sum2);
Optional<Integer> product = lists.stream().reduce((a, b) -> a * b);
if (product.isPresent()) System.out.println("list的積為:" + product.get());//720
Integer product2 = lists.stream().reduce(1, (a, b) -> a * b);
System.out.println("list的積為:" + product2);//720
}
}
這個Demo主要是計算了一個list裡面的總和,積的操作,大家可以和傳統的算總和,積的方法進行對照,比一比衡量一下就有自己的答案了。但是如果你以為流API僅此而已,那你就錯了。越是後面的東西,就越裝B,我在剛知道他們的時候,反正是被嚇了一跳的,但這些都是後話了,現在我們來詳解一下Demo,並給出擴充套件的方向:我們這個例子主要是用了lambda表示式對list進行了求和,求積,對於第一個版本為說,求和的時候,identity的值為0,求積的時候它的值為1,強烈建議你們自己感受一下identity的變化對整個結果的變化產生什麼 的影響,改變一下identity的值,再執行一下,你就有結果了,另一個擴充套件點是:
Integer product3 = lists.stream().reduce(1, (a, b) -> {
if (b % 2 == 0) return a * b; else return a;//這裡你可以為所欲為!
});
System.out.println("list的偶數的積為:" + product3);//48
小結一下
對於流的縮減操作來說,主要要知道,他只返回一個值,並且它是一個終端操作,然後還有的就是要知道縮減操作的三個約束了,其實最重要的就是無狀態性和關聯性了.這一小節要說的,也就這麼多了,應該很容易就把他收到自己的技能樹上面了。
相關文章
- java8 Stream流操作介紹Java
- Java8之Stream常用操作方式Java
- Java8——Stream流Java
- Java8的stream流讓操作集合更容易Java
- Java8 新特性 Stream流操作List集合 (二)Java
- java8新特性stream流Java
- Java8之Stream-強大的collect操作Java
- Java8 Stream流的合併Java
- list轉map,使用java8,stream流Java
- Java8 Lambda 之 Collection StreamJava
- [譯] 一文帶你玩轉 Java8 Stream 流,從此操作集合 So EasyJava
- Java Stream流操作面試題Java面試題
- Java8 的 Stream 流式操作之王者歸來Java
- Java8新特性探索之Stream介面Java
- Java8新特性——從Lambda表示式到Stream流Java
- Java8之Stream-函式式介面Java函式
- Java Stream 流如何進行合併操作Java
- Stream流
- 【Java8新特性】面試官問我:Java8中建立Stream流有哪幾種方式?Java面試
- JDK8新特性之Stream流JDK
- Spring-Web-Flux實戰(三) - Stream 流SpringWebUX
- Java開發工程師進階篇-Java8的Stream流使用技巧Java工程師
- Java8中的Stream APIJavaAPI
- Java8 Stream常用API整理JavaAPI
- Java8的Stream API使用JavaAPI
- Java8新特性--Stream APIJavaAPI
- java8學習:引入streamJava
- 淺析Java8 Stream原理Java
- java8 Stream APi 入門JavaAPI
- Java8中的流操作-基本使用&效能測試Java
- 【Java8新特性】面試官:談談Java8中的Stream API有哪些終止操作?Java面試API
- JAVA基礎之六-Stream(流)簡介Java
- 這麼簡單,還不會使用java8 stream流的map()方法嗎?Java
- Stream流求和
- Java8 Stream完全使用指南Java
- 我是如何理解Java8 StreamJava
- Java8 - Stream API快速入門JavaAPI
- IO流之 檔案操作字元流字元