Spring WebFlux 學(xué)習(xí)筆記 - (一) 前傳:學(xué)習(xí)Java 8 Stream Api (1) - 創(chuàng)建 Stream

影子

在學(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)系如下:

01_stream_diagram.png

創(chuàng)建Stream

創(chuàng)建Stream主要分為如下幾種方式:

  1. 集合獲取Stream
  2. 數(shù)組創(chuàng)建Stream
  3. 值創(chuàng)建Stream
  4. 函數(shù)創(chuàng)建Stream
  5. 其他方式創(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)容,我們下次見。

參考

  1. 【Java8新特性】關(guān)于Java8的Stream API,看這一篇就夠了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容