0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Java的Stream的常用知識

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-11 15:45 ? 次閱讀

什么是Stream

生產(chǎn)線

Stream就像處理生產(chǎn)流水線一樣去工作,傳送帶就是Stream的管道,每個(gè)工廠關(guān)注直接的生產(chǎn),將上游產(chǎn)品加工成下游需要的產(chǎn)品。為什么Stream比傳統(tǒng)的處理方式好呢?我們都知道,傳統(tǒng)的處理中,每一步我們都需要通過循環(huán)控制,邏輯控制,解包,重新裝箱這些工作。

圖片
非生產(chǎn)線示意處理圖

這些步驟讓我們的程序的業(yè)務(wù)邏輯支離破碎,經(jīng)常處理數(shù)據(jù)類的小伙伴尤為痛苦。幸運(yùn)的是,Java8為我們引入了Stream,使用Stream后我們只關(guān)注數(shù)據(jù)處理邏輯,其他的事情交給流處理對應(yīng)的方法來完成。

創(chuàng)建數(shù)據(jù)流

指北君先為大家介紹如何創(chuàng)建Stream,這里有非常多的方式,需要注意一點(diǎn)就是:流一旦創(chuàng)建后,修改創(chuàng)建的源不會影響已經(jīng)創(chuàng)建的Stream中的數(shù)據(jù)。

  1. 空流 為了避免出現(xiàn)空指針異常,系統(tǒng)提供一個(gè)靜態(tài)方法提供空流。
public void createStream() {
        Stream< String > myStream = Stream.empty();
    }
  1. 通過數(shù)組對象創(chuàng)建流
public void createStream() {
        Integer[] arr = new Integer[]{1,2,3};
        Stream< Integer > stream1 = Arrays.stream(arr);
        Stream< Integer > stream2 = Arrays.stream(arr, 0, 2);
    }
  1. 通過集合對象創(chuàng)建流
public void createStream() {
        Collection< String > collection = Arrays.asList("a", "b", "c");
        Stream< String > stream1 = collection.stream();
    }

支持多種集合:List,Set,Map等實(shí)現(xiàn)了Collection接口的集合對象。

  1. 通過builder創(chuàng)建
public void createStream() {
        Stream< Long > stream1 =
                  Stream.< Long >builder().add(1L).add(2L).add(3L).build();
    }
  1. 通過generate生成
public void createStream() {
        Random r = new Random();
        Stream< Long > stream =
                  Stream.generate(() - > r.nextLong()).limit(10);
    }

按照提供給generate的Supplier邏輯生成數(shù)據(jù),通過limit限制生成的數(shù)據(jù)量

  1. 通過Stream.iterate創(chuàng)建
public void createStream() {
        Stream< Integer > stream = Stream.iterate(1, n - > n * n).limit(20);
    }

iterate提供兩種方法來滿足我們比較常用的迭代生成邏輯

  • iterate(final T seed, final UnaryOperatorf)
  • iterate(T seed, Predicate hasNext, UnaryOperatornext)
  1. 原生類型生成 通過對應(yīng)的IntStream,LongStream,DoubleStream類中提供的方法來獲取,包含常用的方法
  • builder()
  • empty()
  • of()
  • iterate()
  • generate()
  • range()
  • concat()
  1. 其他地方 這里介紹兩處:字符分割匹配和文件行數(shù)據(jù)

String.chars()返回IntStream
Files.lines()返回通過行分割的字符內(nèi)容

流的使用機(jī)制(重要事項(xiàng))

我們通過上面的方法創(chuàng)建好流后,就可以對流進(jìn)行相關(guān)的業(yè)務(wù)邏輯處理了,需要注意:如果我們重復(fù)對一個(gè)流進(jìn)行操作,就會出錯,系統(tǒng)會爆出IllegalStateException異常,這是因?yàn)镾tream設(shè)計(jì)為不可重用的模式。流的下一個(gè)環(huán)節(jié)都是對當(dāng)前環(huán)節(jié)處理后新生成流的處理。

流的執(zhí)行順序

采用Stream方式進(jìn)行多個(gè)邏輯處理時(shí),他們之間的執(zhí)行順序是什么樣的呢?指北君為了展示效果,寫了一段測試代碼:

public void exeOrder() {
        List< String > list = Arrays.asList("data_1","data_2", "data_3", "data_12");
        list.stream().filter(x - > {
            System.out.println("filter() was called: " + x);
            return x.contains("2");
        }).map(x - > {
            System.out.println("map() was called: " + x);
            return x.toUpperCase();
        }).forEach(x- >System.out.println("forEach() was called: " + x));
    }

執(zhí)行結(jié)果如下:
filter() was called: data_1
filter() was called: data_2
map() was called: data_2
forEach() was called: data_2
filter() was called: data_3
filter() was called: data_12
map() was called: data_12
forEach() was called: data_12

從示例代碼的打印的順序中我們可以發(fā)現(xiàn):流處理的順序不是以代碼順序(執(zhí)行完一步再到下一步),而是按照數(shù)據(jù)處理完一個(gè)單位數(shù)據(jù)的所有環(huán)節(jié)再處理下一個(gè)數(shù)據(jù),見下面的動態(tài)示意圖:

圖片

Stream處理順序

既然我們了解流的處理順序,也能理解某些流操作會提前結(jié)束流處理的,比如findFirst(),在處理完第一個(gè)符合條件的數(shù)據(jù)后,后續(xù)的數(shù)據(jù)不會參與任何一個(gè)環(huán)節(jié)的處理。

轉(zhuǎn)換處理

轉(zhuǎn)換處理時(shí)最常用的邏輯處理方式,介紹轉(zhuǎn)換處理的文章較多,這里不再一一詳細(xì)描述只是簡單列一下,轉(zhuǎn)換處理對應(yīng)大數(shù)據(jù)MapReduce中的Map處理

  1. distinct剔重
  2. filter過濾
  3. map轉(zhuǎn)換映射
  4. peek
  5. limit
  6. skip

合并處理(reduce)

對于Map-Reduce模型的reduce操作,國內(nèi)對這個(gè)詞翻譯不太統(tǒng)一,指北君就先稱之為合并處理吧。這里介紹兩個(gè)方法reduce和collect

  1. reduce 先來看一個(gè)reduce的示例
public void reduce() {
        int sum = IntStream.range(1, 100).reduce(0, (a, b) - > a + b);
        System.out.print(sum);
    }

合并Stream中的所有值,合并的初始值為0,如果初始為0還可以省略初始值。reduce函數(shù)包含三部分關(guān)鍵信息

  • 初始值,指定合并操作的初始值
  • 合并函數(shù)
  • 合路器(函數(shù)),在并行(多線程)運(yùn)算時(shí)需要用到

下面是一個(gè)使用合路器的示例,在并行運(yùn)算時(shí)使用。

public void parallelReduce() {
        int sum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).parallelStream()
                .reduce(0, (a, b) - > a + b, (a, b) - > {
                   return a + b;
                });
        System.out.println(sum);
    }

這里指北君留一道思考題給大家,如果這里初始值0修改為10,最終的結(jié)果是多少?為什么是這種結(jié)果呢?

  1. collect 現(xiàn)在我們再來看collect,collect嚴(yán)格上說是reduce有些牽強(qiáng),因?yàn)槭欠駌educe在于collect中的執(zhí)行邏輯 比如這段:
List String > collector =  list.stream().map(Product::getName).collect(Collectors.toList());

然后再看下面的例子:

String mergString = list.stream().map(Product::getName).collect(Collectors.joining(", ", "[", "]"));

還有其他對應(yīng)的方法:

  • Collectors.averagingInt
  • Collectors.summingInt
  • Collectors.groupingBy
  • Collectors.partitioningBy

各位小伙伴可以查看Collectors對應(yīng)的API,這里就不一一列舉了,總之,collect通過Collectors對象的API類完成合并處理。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8450

    瀏覽量

    150726
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2952

    瀏覽量

    104489
  • 字符
    +關(guān)注

    關(guān)注

    0

    文章

    232

    瀏覽量

    25154
  • 數(shù)據(jù)處理
    +關(guān)注

    關(guān)注

    0

    文章

    574

    瀏覽量

    28509
  • Stream
    +關(guān)注

    關(guān)注

    0

    文章

    20

    瀏覽量

    7956
收藏 人收藏

    評論

    相關(guān)推薦

    Stream模塊的基礎(chǔ)用法和進(jìn)階用法

    在 Rust 語言中,Tokio 是一個(gè)非常流行的異步編程框架。它提供了一系列的模塊,其中最常用的就是 Stream 模塊。Stream 模塊允許我們以異步的方式處理數(shù)據(jù)流,這在很多情況下非常
    的頭像 發(fā)表于 09-19 15:33 ?1133次閱讀

    Stream API原理介紹

    Stream API 是 Java 8 中最重要的新特性之一,它是處理集合和數(shù)組的一種新方式。它提供了一種簡單、靈活和可讀的方式來處理集合和數(shù)組中的元素,從而使代碼更加簡潔、高效和易于維護(hù)。 1.
    的頭像 發(fā)表于 09-30 15:31 ?664次閱讀

    JAVA學(xué)習(xí)直通車(教程+書籍+100個(gè)實(shí)例+問題與解答)

    對于Java8的并行流并不陌生,沒錯,我們常常用它來執(zhí)行并行任務(wù),但是由于并行流(parallel stream)采用的是享線程池,可能會對我們的性能造成嚴(yán)重影響,那怎么處理呢?`
    發(fā)表于 10-25 14:35

    JAVA常用系統(tǒng)類的使用 實(shí)驗(yàn)

    實(shí)驗(yàn) 6 常用系統(tǒng)類的使用 一、實(shí)驗(yàn)?zāi)康?了解 Java 常用的系統(tǒng)類,包括 Java Applet、字符串類、輸入輸出流類、數(shù)學(xué)函數(shù)類、日期類、隨機(jī)數(shù)類以及向量類等的基
    發(fā)表于 09-23 19:01 ?1734次閱讀

    Java常用工具類

    Java常用工具類。
    發(fā)表于 11-06 11:21 ?1次下載

    JAVA教程之常用圖形的繪制與填充

    JAVA教程之常用圖形的繪制與填充,很好的JAVA的資料,快來學(xué)習(xí)吧
    發(fā)表于 04-11 17:28 ?3次下載

    JAVA相關(guān)基礎(chǔ)知識

    JAVA相關(guān)基礎(chǔ)知識,感興趣的小伙伴們可以瞧一瞧。
    發(fā)表于 11-10 11:17 ?0次下載

    Java設(shè)計(jì)知識講解

    本文檔內(nèi)容介紹了基于Java設(shè)計(jì)知識講解,供參考
    發(fā)表于 03-26 11:09 ?16次下載

    如何利用Stream API來優(yōu)化Java代碼

    使用Stream API優(yōu)化代碼 Java8的新特性主要是Lambda表達(dá)式和流,當(dāng)流和Lambda表達(dá)式結(jié)合起來一起使用時(shí),因?yàn)榱魃昝魇教幚頂?shù)據(jù)集合的特點(diǎn),可以讓代碼變得簡潔易讀 放大招,流
    的頭像 發(fā)表于 07-26 14:30 ?1270次閱讀

    JDK8 Stream數(shù)據(jù)流效率分析

    StreamJava SE 8類庫中新增的關(guān)鍵抽象,它被定義于 java.util.stream (這個(gè)包里有若干流類型:Stream 代表對象引用流,此外還有一系列特化流,
    的頭像 發(fā)表于 08-17 10:53 ?1201次閱讀

    javastream編程調(diào)試技巧

      javastream編程給調(diào)試帶來了極大的不便,idea 推出了streamtrace功能,可以詳細(xì)看到每一步操作的關(guān)系、結(jié)果,非常方便進(jìn)行調(diào)試。初遇StreamTrace這里簡單將字符串轉(zhuǎn)成它的字符數(shù),并設(shè)置斷點(diǎn)開啟debug模式。
    的頭像 發(fā)表于 10-11 11:06 ?1539次閱讀

    淺析Stream里的隱式轉(zhuǎn)換

    Stream、Flow是在電路描述里經(jīng)常用到的對象。
    的頭像 發(fā)表于 05-15 17:36 ?445次閱讀
    淺析<b class='flag-5'>Stream</b>里的隱式轉(zhuǎn)換

    怎么使用Java8的Stream API比較兩個(gè)List的差異呢?

    可以使用Java8的Stream API來比較兩個(gè)List的差異,并取出不同的對象。
    的頭像 發(fā)表于 08-12 11:15 ?2144次閱讀

    Java8的Stream流 map() 方法

    8 之后,對集合可以進(jìn)行 Stream 操作,使上面的處理更簡潔。 概述 Stream 流式處理中有 map() 方法,先看下其定義,該方法在java.util.stream.Stream類中 可以看到
    的頭像 發(fā)表于 09-25 11:06 ?1733次閱讀
    <b class='flag-5'>Java</b>8的<b class='flag-5'>Stream</b>流 map() 方法

    java常用的包有哪些

    Java是一種面向?qū)ο蟮母呒壘幊陶Z言,它具有平臺無關(guān)性和可擴(kuò)展性。Java中有很多常用的包,這些包提供了豐富的類庫和工具,用于開發(fā)各種類型的應(yīng)用程序。下面是Java中一些
    的頭像 發(fā)表于 11-22 15:10 ?1288次閱讀