影子
在學(xué)習(xí)Spring WebFlux之前,我們先來了解JDK的Stream,雖然他們之間沒有直接的關(guān)系,有趣的是 Spring Web Flux 基于 Reactive Stream,他們中都帶了 Stream?,F(xiàn)有需求如下:篩選出一個(gè)數(shù)組中的偶數(shù),每個(gè)增加 100 后輸出到控制臺(tái),我們來看下使用JDK Stream和使用Reactor(Reactive Stream的一種實(shí)現(xiàn),后面會(huì)講)編寫的代碼:
// JDK Stream實(shí)現(xiàn)
Arrays.stream(ARRAY)
.filter(num -> num % 2 == 0)
.map(num -> num + 100)
.forEach(System.out::println);
// Reactor實(shí)現(xiàn)
Flux.fromArray(ARRAY)
.filter(num -> num % 2 == 0)
.map(num -> num + 100)
.subscribe(System.out::println);
以上代碼見JdkStreamAndReactorTest。
我們發(fā)現(xiàn)他們的寫法是相似的,都是采用函數(shù)式編程,并且其中有很多函數(shù)(操作符)是一樣的,拋除他們的異同點(diǎn)(后面會(huì)講),我們先來了解下 Java8 的 Stream API,方便我們后面可以更快的了解 Reactor 中的各種操作符。
Stream API
Java8中有兩大最為重要的改變:第一個(gè)是 Lambda 表達(dá)式;另外一個(gè)則是 Stream API(java.util.stream.*)。
Stream Api 位于 java.util.stream 包下,Stream接口是該包下的關(guān)鍵抽象。Stream、IntStream、LongStream、DoubleStream 分別是Object(支持泛型))、int(整數(shù))、long(長(zhǎng)整數(shù))、double(雙精度浮點(diǎn)數(shù))類型的數(shù)據(jù)流抽象。
流在如下幾個(gè)方面與集合不同:
- 不做存儲(chǔ)。流不是存儲(chǔ)元素的數(shù)據(jù)結(jié)構(gòu)。相反,它從諸如數(shù)據(jù)結(jié)構(gòu)、數(shù)組、生成函數(shù)或I/O通道之類的源中通過一系列計(jì)算操作(向流管道中)傳遞元素。
- 函數(shù)式的。對(duì)流的操作會(huì)產(chǎn)生結(jié)果,但不會(huì)修改源數(shù)據(jù)。例如,對(duì)從集合中獲取的Stream進(jìn)行過濾會(huì)生成一個(gè)不帶過濾元素的新Stream,而不是從源集合中刪除元素。
- 懶惰操作。許多流操作(例如過濾,映射或重復(fù)刪除)總是延遲操作,從而找到優(yōu)化的機(jī)會(huì)。例如,“查找以某三個(gè)字母開頭的第一個(gè)字符串”不需要檢查所有輸入字符串。流操作分為中間(流產(chǎn)生)操作和終端(產(chǎn)生值或副作用)操作。中間操作總是惰性的。
- 可能無界。盡管集合的大小是有限的,但流不是必需的。諸如 limit(n) 或 findFirst() 之類的短路操作可以允許對(duì)無限流的計(jì)算在有限時(shí)間內(nèi)完成。
- 消耗品。在流的生存期內(nèi),流的元素只能訪問一次。像Iterator一樣,必須生成新的流以重新訪問源中的相同元素。
Stream 是 Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。使用Stream API 對(duì)集合數(shù)據(jù)進(jìn)行操作,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫(kù)查詢。也可以使用 Stream API 來并行執(zhí)行操作。簡(jiǎn)而言之,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
Stream的用法
1. 創(chuàng)建 Stream
一個(gè)數(shù)據(jù)源(如:集合、數(shù)組), 獲取一個(gè)流。
2. 中間操作
一個(gè)中間操作鏈,對(duì)數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理。
3. 終端操作(終止操作)
一個(gè)終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果 。
Stream的分類
| 序號(hào) | 類名 | 說明 |
|---|---|---|
| 1 | BaseStream | Stream接口的父接口 |
| 2 | Stream<T> | 泛型類型的Stream |
| 3 | IntStream | 整形Stream |
| 4 | LongStream | 長(zhǎng)整型Stream |
| 5 | DoubleStream | 浮點(diǎn)型Stream |
序號(hào)3-5的具體類型Stream提供了一些額外的方法,在下面章節(jié)【創(chuàng)建Stream】時(shí)有用到。它們之間的類圖關(guān)系如下:

創(chuàng)建Stream
創(chuàng)建Stream主要分為如下幾種方式:
- 集合獲取Stream
- 數(shù)組創(chuàng)建Stream
- 值創(chuàng)建Stream
- 函數(shù)創(chuàng)建Stream
- 其他方式創(chuàng)建Stream
由于篇幅問題及考慮到Stream提供的操作方法沒有講解,下面的示例代碼中只是提供了創(chuàng)建Stream的示例,具體的使用示例請(qǐng)看代碼。
注意:以下創(chuàng)建Stream的方式僅為演示使用,因?yàn)镾tream進(jìn)行中間操作或終端操作后就會(huì)關(guān)閉,不可重復(fù)使用,因此你在使用的時(shí)候應(yīng)該按函數(shù)式編程方式編寫代碼。
1. 集合獲取Stream
// 返回以此集合作為源的順序 Stream
Stream<Integer> stream = collection.stream();
// 返回以此集合作為其來源可能并行的 Stream
Stream<Integer> parallelStream = collection.parallelStream();
2. 數(shù)組創(chuàng)建Stream
// 創(chuàng)建數(shù)組Stream
Stream<String> stream = Arrays.stream(strArray);
IntStream intStream = Arrays.stream(intArray);
// 數(shù)組Stream的重載
DoubleStream doubleStream = Arrays.stream(doubleArray);
IntStream intStream2 = Arrays.stream(intArray, 1, 3);
3. 值創(chuàng)建Stream
// 構(gòu)建Integer類型的Stream
IntStream stream = IntStream.of(14, 2, 31, 47, 5, 6, 9, 1, 33, 2, 6);
// 構(gòu)建String類型的Stream
Stream<String> stringStream = Stream.of("Hello, Stream Api.");
4. 函數(shù)創(chuàng)建Stream
// 方式1:使用generate方式創(chuàng)建一個(gè)新的無限無序Stream流
Stream<Integer> generateStream = Stream.generate(RandomUtil::randomInt);
// 方式2:使用iterate方式創(chuàng)建一個(gè)新的無限有序Stream流
IntStream iterateStream = IntStream.iterate(1, n -> n + 1);
5. 其他方式創(chuàng)建Stream
// 方式1:創(chuàng)建空的順序流
Stream<Object> emptyStream = Stream.empty();
// 方式2:使用兩個(gè)Stream創(chuàng)建組合Stream
IntStream concatStream = IntStream.concat(intStream1, intStream2);
// 方式3:創(chuàng)建begin至end逐漸加1的整形Stream
IntStream rangeStream = IntStream.range(1, 501);
// 方式4:使用建造者模式創(chuàng)建Stream
Stream.Builder<Integer> builder = Stream.builder();
Stream<Integer> buildStream = builder.build();
// 方式5:使用StreamSupport創(chuàng)建Stream
// 代碼忽略,具體使用請(qǐng)看API...
以上代碼見CreateStreamTest。
源碼詳見:https://github.com/crystalxmumu/spring-web-flux-study-note
以上是本次筆記的內(nèi)容,我們下次見。