Java8 stream流操作(上)

本文是我在學習Java8的時候參考下面大佬的文章拷貝的台盯,僅用于個人整理和學習用途
原文地址:http://www.reibang.com/p/0bb4daf6c800

一. 什么是 Stream

Stream 中文稱為“流”江滨,通過將集合轉(zhuǎn)換為這么一種叫做 “流” 的元素序列,通過聲明性方式盲憎,能夠?qū)现械拿總€元素進行一系列并行或串行的流水線操作。

換句話說,你只需要告訴流你的要求塞椎,流便會在背后自行根據(jù)要求對元素進行處理唱凯,而你只需要 “坐享其成”羡忘。

二. 流操作

image

整個流操作就是一條流水線,將元素放在流水線上一個個地進行處理磕昼。

其中數(shù)據(jù)源便是原始集合卷雕,然后將如 List<T> 的集合轉(zhuǎn)換為 Stream<T> 類型的流,并對流進行一系列的中間操作票从,比如過濾保留部分元素漫雕、對元素進行排序、類型轉(zhuǎn)換等纫骑;最后再進行一個終端操作蒙袍,可以把 Stream 轉(zhuǎn)換回集合類型浸须,也可以直接對其中的各個元素進行處理,比如打印、比如計算總數(shù)恩袱、計算最大值等等

很重要的一點是,很多流操作本身就會返回一個流痢甘,所以多個操作可以直接連接起來馍刮,我們來看看一條 Stream 操作的代碼:

image

如果是以前,進行這么一系列操作仿野,你需要做個迭代器或者 foreach 循環(huán)铣减,然后遍歷,一步步地親力親為地去完成這些操作脚作;但是如果使用流葫哗,你便可以直接聲明式地下指令缔刹,流會幫你完成這些操作。

有沒有想到什么類似的劣针?是的校镐,就像 SQL 語句一樣,select username from user where id = 1捺典,你只要說明:“我需要 id 是 1 (id = 1)的用戶(user)的用戶名(username)”鸟廓,那么就可以得到自己想要的數(shù)據(jù),而不需要自己親自去數(shù)據(jù)庫里面循環(huán)遍歷查找襟己。

三.方法介紹與實踐:

1.獲取流:stream() / parallelStream()

   List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
   Stream<Integer> stream = asList.stream();
   System.out.println(stream);

輸出結(jié)果:
clipboard.png

XX.stream() 方法獲取的是流引谜,然而我們在實際開發(fā)中一般需要獲取的是集合

2.流轉(zhuǎn)換為集合:collect(Collectors.toList())

    List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
    List<Integer> collect1 = asList.stream().collect(Collectors.toList());
    List<Integer> collect2 = asList.stream().collect(toList());
    System.out.println(collect1);
    System.out.println(collect2);

輸出結(jié)果: 這兩種寫法獲取的結(jié)果都是一樣的,第二種為簡寫


clipboard.png

3.排序 sorted()

eg1:

    List<Integer> asList = Arrays.asList(10, 20, 30, 40, 50);
    List<Integer> asc = asList.stream().sorted().collect(toList()); //正序
    List<Integer> desc = asList.stream().sorted(Comparator.reverseOrder()).collect(toList());//倒序
    System.out.println(asc);
    System.out.println(desc);

輸出結(jié)果:
clipboard.png

eg2:使用mybatis-plus 查詢后對獲得的數(shù)組中的某個字段進行排序(數(shù)據(jù)有點多截取了前5條數(shù)據(jù)進行排序)

    List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<>()); //查詢表中所有數(shù)據(jù)
    ////按照ATag中SerialNumber字段排序
    List<ATag> collect1 = aTags.stream().sorted(Comparator.comparing(ATag::getSerialNumber)).limit(5).collect(toList());
    List<ATag> collect2 = aTags.stream().sorted(Comparator.comparing(ATag::getSerialNumber).reversed()).limit(5).collect(toList());
    collect1.forEach(System.out::println);
    System.out.println("----------分割線------------");
    collect2.forEach(System.out::println);

輸出結(jié)果:


360截圖20200416173801798.jpg

4.去重 distinct()

eg1:

    List<Integer> asList = Arrays.asList(10,10,20,20,30,40,50);
    asList.stream().distinct().collect(toList()).forEach(System.out::println);

輸出:

360截圖20200416174543939.jpg

eg2:
如果想要對 List<Object> 中某個字段進行去重這里使用 distinct(類::字段) 這種方法是不行的(沒有這種篩選條件)
因此擎浴,需要借助一下過濾器以及下面學到的filter()方法员咽,實現(xiàn)對 List<Object> 中根據(jù)某個字段進行去重
參考文章:http://www.reibang.com/p/77c3b503730c

        //過濾器:
        public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
            ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>(16);
            return t -> map.putIfAbsent(keyExtractor.apply(t),Boolean.TRUE) == null;
        }

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));//查詢表中serial_number=6的數(shù)據(jù)
        aTags.forEach(System.out::println);
        System.out.println("-------------------------分割線-------------------------");
        aTags.stream().filter(distinctByKey(ATag::getNameZh)).collect(toList()).forEach(System.out::println);

輸出 :
xx.jpg

5.過濾 filter()

保留 boolean 為 true 的元素

       //查詢表中serial_number=6的數(shù)據(jù)
        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割線-------------------------");
        aTags.stream().filter(x->x.getNameZh().equals("御坂美琴")).collect(toList()).forEach(System.out::println); 

輸出:
11.jpg

6.截取(返回前 n 個元素) limit(long n)

        //查詢表中serial_number=6的數(shù)據(jù)
        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割線-------------------------");
        aTags.stream().limit(2).forEach(System.out::println);

輸出結(jié)果:
image.png

7.跳過 skip(long n)

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().skip(1).limit(2).collect(toList()));

這里使用了skip()和limit()

輸出結(jié)果:
360截圖20200417100638948.jpg

tips:

用在 limit(n) 前面時退客,先去除前 m 個元素再返回剩余元素的前 n 個元素
limit(n) 用在 skip(m) 前面時骏融,先返回前 n 個元素再在剩余的 n 個元素中去除 m 個元素

8. map(T -> R)

將流中的每一個元素 T 映射為 R(類似類型轉(zhuǎn)換)
eg1:

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割線-------------------------");
        aTags.stream().map(ATag::getNameZh).collect(toList()).forEach(System.out::println);

這里相當于把List<ATag>轉(zhuǎn)換為List<String>

輸出:
360截圖20200417101622995.jpg
eg2:
        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        List<Integer> collect = asList.stream().map(x -> x + x * 0.1).mapToInt(T -> T.intValue()).boxed().collect(toList());

輸出:
1.jpg

9. flatMap(T -> Stream<R>)

將流中的每一個元素 T 映射為一個流,再把每一個流連接成為一個流

List<String> list = new ArrayList<>();
list.add("aaa bbb ccc");
list.add("ddd eee fff");
list.add("ggg hhh iii");
list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());

上面例子中萌狂,我們的目的是把 List 中每個字符串元素以" "分割開档玻,變成一個新的 List<String>。
首先 map 方法分割每個字符串元素茫藏,但此時流的類型為 Stream<String[ ]>误趴,因為 split 方法返回的是 String[ ] 類型;所以我們需要使用 flatMap 方法务傲,先使用Arrays::stream將每個 String[ ] 元素變成一個 Stream<String> 流凉当,然后 flatMap 會將每一個流連接成為一個流,最終返回我們需要的 Stream<String>

10.anyMatch(T -> boolean)

流中是否有一個元素匹配給定的 T -> boolean 條件

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割線-------------------------");
        System.out.println(aTags.stream().anyMatch(x -> x.getNameEn().equals("Misaka Miko")));

輸出:
360截圖20200417102715580.jpg

11. allMatch(T -> boolean)

流中是否所有元素都匹配給定的 T -> boolean 條件,當流中所有元素都符合條件的時候才返回true

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().allMatch(x -> x >= 10));

輸出:
360截圖20200417103151762.jpg

12.noneMatch(T -> boolean)

流中是否沒有元素匹配給定的 T -> boolean 條件(流中有元素匹配到條件返回true否則返回false)

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().noneMatch(x -> x >= 10));

輸出:


b.jpg

13. findAny() 和 findFirst()

findAny():找到其中一個元素 (使用 stream() 時找到的是第一個元素售葡;使用 parallelStream() 并行時找到的是其中一個元素)
findFirst():找到第一個元素

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        System.out.println(asList.stream().findFirst());
        System.out.println(asList.stream().findAny());
        System.out.println(asList.parallelStream().findAny());

輸出:


c.jpg

14.reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)

用于組合流中的元素看杭,如求和,求積挟伙,求最大值等

eg1:其中楼雹,reduce 第一個參數(shù) 0 代表起始值為 0,lambda (a, b) -> a + b 即將兩值相加產(chǎn)生一個新值

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割線-------------------------");
        System.out.println(aTags.stream().map(ATag::getParentId).reduce(0L, Long::sum));

輸出:
2.jpg

eg2:
如果沒有初始值尖阔,需要考慮結(jié)果可能不存在的情況贮缅,因此返回的是 Optional 類型如果不需要這種返回類型設(shè)置初始值即可

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        Integer reduce1 = asList.stream().reduce(0, (x, y) -> x + y);
        Integer reduce2 = asList.stream().mapToInt(T -> T.intValue()).boxed().reduce(0, (x, y) -> x + y);
        Optional<Integer> reduce3 = asList.stream().reduce((x, y) -> x + y);
        System.out.println("reduce1:"+reduce1 +"\n"+ "reduce2:"+reduce2+"\n"+"reduce3:"+reduce3);

15. count()

返回流中元素個數(shù),結(jié)果為 long 類型

        List<Integer> asList = Arrays.asList(10,20,30,40,50);
        asList.stream().count();

16.遍歷流中的每一個元素 forEach()

當然我們也可以通過forEach()遍歷流中的每一個元素介却,然后注入Mapper對流中元素進行CRUD

        List<ATag> aTags = aTagMapper.selectList(new QueryWrapper<ATag>().eq("serial_number",6));
        aTags.forEach(System.out::println);
        System.out.println("-------------------分割線-------------------------");
        aTags.stream().forEach(item->{
            System.out.println(item.getNameZh());
        });

輸出:
3.jpg

文章出處
作者:Howie_Y
鏈接:http://www.reibang.com/p/0bb4daf6c800
來源:簡書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谴供,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子齿坷,更是在濱河造成了極大的恐慌桂肌,老刑警劉巖数焊,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異轴或,居然都是意外死亡昌跌,警方通過查閱死者的電腦和手機仰禀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門照雁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人答恶,你說我怎么就攤上這事饺蚊。” “怎么了悬嗓?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵污呼,是天一觀的道長。 經(jīng)常有香客問我包竹,道長燕酷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任周瞎,我火速辦了婚禮苗缩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘声诸。我一直安慰自己酱讶,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布彼乌。 她就那樣靜靜地躺著泻肯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慰照。 梳的紋絲不亂的頭發(fā)上灶挟,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機與錄音毒租,去河邊找鬼稚铣。 笑死,一個胖子當著我的面吹牛蝌衔,可吹牛的內(nèi)容都是我干的榛泛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼噩斟,長吁一口氣:“原來是場噩夢啊……” “哼曹锨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起剃允,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤沛简,失蹤者是張志新(化名)和其女友劉穎齐鲤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體椒楣,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡给郊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捧灰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淆九。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖毛俏,靈堂內(nèi)的尸體忽然破棺而出炭庙,到底是詐尸還是另有隱情,我是刑警寧澤煌寇,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布焕蹄,位于F島的核電站,受9級特大地震影響阀溶,放射性物質(zhì)發(fā)生泄漏腻脏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一银锻、第九天 我趴在偏房一處隱蔽的房頂上張望永品。 院中可真熱鬧,春花似錦徒仓、人聲如沸腐碱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽症见。三九已至,卻和暖如春殃饿,著一層夾襖步出監(jiān)牢的瞬間谋作,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工乎芳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留遵蚜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓奈惑,卻偏偏與公主長得像吭净,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子肴甸,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容