Java 8 Stream API

Java 8 Stream API

package com.excmmy.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class test1 {
    public static void main(String[] args) {
        testMatch();
    }

    public static void testMap() {
        /*
        * map()
        * 將每個 stream 的元素 映射成另外一個元素
        * */
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> newNums = nums.stream().map(item -> item * item).collect(Collectors.toList());
        System.out.println(newNums);
    }

    public static void testFlatMap() {
        /*
        * flatMap() 將 input 中的層級機構扁平化, 就是將最底層的元素抽出來放到一起
        * */
        List<Integer> num1 = Arrays.asList(1, 10);
        List<Integer> num2 = Arrays.asList(1, 2, 3);
        List<Integer> num3 = Arrays.asList(2, 3, 4, 5);
        Stream<List<Integer>> input = Stream.of(num1, num2, num3);
        List<Integer> collect = input.flatMap(item -> item.stream()).collect(Collectors.toList());
        System.out.println(collect);
    }

    public static void testFilter() {
        /*
        * filter()
        * 對原始 Stream 進行某項測試, 通過測試的元素被留下來生成一個新的 Stream, Lambda后面跟的是一個表達式, 條件為真的時候返回
        * */
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        List<Integer> collect = nums.stream().filter(item -> {
            if ((item * 2) > 5) {
                return true; // true 返回當前 item
            }
            return false; // false 不返回
        }).collect(Collectors.toList());
        System.out.println(collect);
    }

    public static void testForEach() {
        /*
        * forEach()
        * forEach方法接收一個 Lambda 表達式, 然后在 Stream 的每一個元素上執(zhí)行該表達式
        * 當需要為多核心優(yōu)化時, 可以使用 parallelStream().forEach(), 只是此時原有元素的次序沒法保證
        * forEach是terminal操作, 它執(zhí)行后, Stream 的元素就被"消費"掉了, 也就是說 forEach 在 Stream中 只能使用一次, 并且在最后一次使用
        * forEach 不能修改自己包含的本地變量值, 也不能用break/return之類的關鍵字提前結束循環(huán)
        *
        * peak()
        * 與 forEach() 相同, 但是 它不是terminal操作, 可以繼續(xù)執(zhí)行其他操作
        * */
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        nums.stream().filter(item -> {
            if ((item * 2) > 5) {
                return true; // true 返回當前 item
            }
            return false; // false 不返回
        }).forEach(System.out::println);
    }

    public static void testFindFirst() {
        /*
        * Optional.ofNullable()
        * 返回值類型Optional, 作為一個容器, 它可能含有某值, 或者不包含, 使用它的目的是盡可能避免NullPointerException
        * */
        String text = null;
        Integer integer = Optional.ofNullable(text).map(String::length).orElse(-1);
        System.out.println(integer);
    }

    public static void testReduce() {
        /*
        * reduce()
        * 主要作用是把Stream元素組合起來, 它提供一個起始值,
        * 然后依照運算規(guī)則(BinaryOperator)冲粤,和前面 Stream 的第一個珠移、第二個娱仔、第n個元素組合
        * 示例中, 相當于求所有的和
        * */
        List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        Integer reduce = nums.stream().reduce(0, (item1, item2) -> item1 + item2);
        System.out.println(reduce);

        // 字符串連接, concat = "ABCD", 第一個參數(shù)(空白字符)即為起始值
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        System.out.println(concat);

        // 求和, sumValue = 10, 有起始值
        int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
        System.out.println(sumValue);

        // 求和, sumValue2 = 10, 無起始值, 由于可能沒有足夠的元素,返回的是 Optional
        int sumValue2 = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
        System.out.println(sumValue2);
    }

    public static void testLimitAndSkip() {
        /*
        * limit() / skip()
        * limit 返回 Stream 的前面 n 個元素
        * skip 則是扔掉前 n 個元素
        * */
        List<Person> persons = new ArrayList();
        for (int i = 1; i <= 10000; i++) {
            Person person = new Person(i, "name" + i);
            persons.add(person);
        }
        List<String> personList2 = persons.stream().
                map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
        System.out.println(personList2);
    }

    public static void testLimitAndSkip2() {
        /*
        * limit() / skip()
        * 把它們放在 Stream 的排序操作后無法達到 short-circuiting 目的
        * 此時系統(tǒng)并不知道 Stream 排序后的次序如何, 所以 sorted 中的操作看上去就像完全沒有被limit或者skip一樣
        * */
        List<Person> persons = new ArrayList();
        for (int i = 1; i <= 5; i++) {
            Person person = new Person(i, "name" + i);
            persons.add(person);
        }
        List<Person> personList2 = persons.stream().sorted((p1, p2) ->
                p1.getName().compareTo(p2.getName())).limit(2).collect(Collectors.toList());
        System.out.println(personList2);
    }

    public static void testSorted() {
        /*
        * sorted()
        * 對 Stream 的排序通過 sorted 進行
        * 它比數(shù)組的排序更強之處在于你可以首先對Stream進行各類map猛拴、filter稳衬、limit霞捡、skip甚至distinct來減少元素數(shù)量后再排序
        * 當然, 這種優(yōu)化是有business logic上的局限性的: 即不要求排序后再取值
        * */
        List<Person> persons = new ArrayList();
        for (int i = 1; i <= 5; i++) {
            Person person = new Person(i, "name" + i);
            persons.add(person);
        }

        List<Person> personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
        System.out.println(personList2);
    }

    public static void testMatch() {
        /*
        * allMatch:Stream 中全部元素符合傳入的 predicate,返回 true;
        * anyMatch:Stream 中只要有一個元素符合傳入的 predicate薄疚,返回 true;
        * noneMatch:Stream 中沒有一個元素符合傳入的 predicate碧信,返回 true.
        * */
        List<Person> persons = new ArrayList();
        persons.add(new Person(1, "name" + 1, 10));
        persons.add(new Person(2, "name" + 2, 21));
        persons.add(new Person(3, "name" + 3, 34));
        persons.add(new Person(4, "name" + 4, 6));
        persons.add(new Person(5, "name" + 5, 55));

        boolean isAllAdult = persons.stream().allMatch(p -> p.getAge() > 18);
        System.out.println("All are adult? " + isAllAdult);
        boolean isThereAnyChild = persons.stream().anyMatch(p -> p.getAge() < 12);
        System.out.println("Any child? " + isThereAnyChild);
    }

    private static class Person {
        public int no;
        private String name;
        private int age;

        public Person(int no, String name) {
            this.no = no;
            this.name = name;
        }

        public Person(int no, String name, int age) {
            this.no = no;
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

Stream 的特性可以歸納為:

  • 不是數(shù)據(jù)結構;
  • 它沒有內(nèi)部存儲,它只是用操作管道從source(數(shù)據(jù)結構街夭、數(shù)組砰碴、generator function、IO channel)抓取數(shù)據(jù);
  • 它也絕不修改自己所封裝的底層數(shù)據(jù)結構的數(shù)據(jù)板丽。例如Stream的filter操作會產(chǎn)生一個不包含被過濾元素的新Stream呈枉,而不是從source刪除那些元素;
  • 所有Stream的操作必須以lambda表達式為參數(shù);
  • 不支持索引訪問;
  • 你可以請求第一個元素,但無法請求第二個檐什,第三個,或最后一個;
  • 很容易生成數(shù)組或者List;
  • 惰性化;
  • 很多Stream操作是向后延遲的弱卡,一直到它弄清楚了最后需要多少數(shù)據(jù)才會開始;
  • Intermediate操作永遠是惰性化的;
  • 并行能力;
  • 當一個 Stream 是并行化的乃正,就不需要再寫多線程代碼,所有對它的操作會自動并行進行的;
  • 可以是無限的婶博。集合有固定大小瓮具,Stream 則不必。limit(n)和findFirst()這類的short-circuiting操作可以對無限的Stream進行運算并很快完成凡人。
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末名党,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子挠轴,更是在濱河造成了極大的恐慌传睹,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岸晦,死亡現(xiàn)場離奇詭異欧啤,居然都是意外死亡,警方通過查閱死者的電腦和手機启上,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門邢隧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冈在,你說我怎么就攤上這事倒慧。” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵纫谅,是天一觀的道長炫贤。 經(jīng)常有香客問我,道長系宜,這世上最難降的妖魔是什么照激? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮盹牧,結果婚禮上俩垃,老公的妹妹穿的比我還像新娘。我一直安慰自己汰寓,他們只是感情好口柳,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著有滑,像睡著了一般跃闹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毛好,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天望艺,我揣著相機與錄音,去河邊找鬼肌访。 笑死找默,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的吼驶。 我是一名探鬼主播惩激,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蟹演!你這毒婦竟也來了风钻?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤酒请,失蹤者是張志新(化名)和其女友劉穎骡技,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羞反,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡哮兰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了苟弛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喝滞。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膏秫,靈堂內(nèi)的尸體忽然破棺而出右遭,到底是詐尸還是另有隱情做盅,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布窘哈,位于F島的核電站吹榴,受9級特大地震影響,放射性物質發(fā)生泄漏滚婉。R本人自食惡果不足惜图筹,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望让腹。 院中可真熱鬧远剩,春花似錦、人聲如沸骇窍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腹纳。三九已至痢掠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘲恍,已是汗流浹背足画。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留佃牛,地道東北人淹辞。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像吁脱,于是被迫代替她去往敵國和親桑涎。 傳聞我的和親對象是個殘疾皇子彬向,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

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