Java流操作總結(jié)

Java流(Stream)操作自Java 8引入蚀浆,通過Stream操作可以簡化代碼編寫,提高代碼執(zhí)行效率搜吧。流整體操作分為創(chuàng)建(Supplier)市俊、轉(zhuǎn)換、約簡和收集幾個操作滤奈。

創(chuàng)建流

創(chuàng)建流最常見的方式是調(diào)用Collection.stream()方法摆昧,將集合數(shù)據(jù)轉(zhuǎn)換為流,也可以通過generate方法創(chuàng)建流蜒程。如下所示:

    public static void main(String[] args) {
        //從Collection中產(chǎn)生流
        ArrayList<String> strings = new ArrayList<>();
        for (int i = 0; i < 20; ++i) {
            strings.add("string" + i);
        }

        Stream<String> stringStream = strings.stream();
        show("stringStream", stringStream);

        //使用generate產(chǎn)生流
        Stream<Integer> integerStream = Stream.generate(() -> (int) (Math.random() * 100));
        show("integerStream", integerStream);
        //使用iterate產(chǎn)生序列
        Stream<Integer> integerStream1 = Stream.iterate(0, n -> n + 1);
        show("integerStream1", integerStream1);

        //使用of方法創(chuàng)建流
        Stream<String> stringStream1 = Stream.of("Bob", "Mark", "Alice", "Edd");
        show("stringStream1", stringStream1);

        //正則表達(dá)式產(chǎn)生流
        String sentences = "I had a dog whose name was Bingo. B, I, N, G, O, Bingo was his name, Oh!";
        Stream<String> words = Pattern.compile("\\PL+").splitAsStream(sentences);
        show("PatterStream", words);
    }

    public static<T> void show(String title, Stream<T> stream) {
        final int size = 10;
        List<T> array = stream.limit(size).collect(Collectors.toList());
        System.out.println(title + ": ");
        for (int i = 0; i < array.size(); ++i) {
            if (i > 0) {
                System.out.print(", ");
            }
            if (i < array.size()) {
                System.out.print(array.get(i));
            } else {
                System.out.print("...");
            }
        }
        System.out.println();
    }   

流的轉(zhuǎn)換

流的轉(zhuǎn)換即將一個給定的流通過流的方法轉(zhuǎn)換為另一個流绅你,常見的方法有filter,map昭躺,distinct, sorted忌锯,reverse等方法。

  • filter方法保留滿足filter方法中的條件表達(dá)式的元素领炫;
  • map方法可以對流中的元素進(jìn)行一個轉(zhuǎn)換操作偶垮;
  • distinct方法將流中重復(fù)的元素去除
  • sorted按給定的比較方法進(jìn)行排序
String sentences = "I had a dog whose name was Bingo. B, I, N, G, O, Bingo was his name, Oh!";
//保留長度大于2的單詞
Stream<String> words1 = Pattern.compile("\\PL+").splitAsStream(sentences).filter(s -> s.length() > 2);
show("PatterStream1", words1);

//將單詞轉(zhuǎn)換為大寫
Stream<String> words2 = Pattern.compile("\\PL+").splitAsStream(sentences).map(String::toUpperCase);
show("PatterStream2", words2);

//去除重復(fù)的單詞
Stream<String> words3 = Pattern.compile("\\PL+").splitAsStream(sentences).distinct();
show("PatterStream3", words3);

//按長度對單詞進(jìn)行排序
Stream<String> words4 = Pattern.compile("\\PL+").splitAsStream(sentences).sorted(Comparator.comparing(String::length));
show("PatterStream4", words4);

 //按長度對單詞進(jìn)行排序后反序
 Stream<String> words5 = Pattern.compile("\\PL+").splitAsStream(sentences).sorted(Comparator.comparing(String::length).reversed());
 show("PatterStream4", words5);

流的約減(Reduce)

流經(jīng)過處理后,提供了一系列方法從流中抽取數(shù)據(jù)。抽取數(shù)據(jù)是一種終結(jié)操作针史,常用的方法如下:

  • count方法:獲取流中滿足條件的元素個數(shù)
  • min晶伦、max方法:按照給定的比較方法獲取最小最大值,注意該方法返回的是一個Optional<T>的包裝類啄枕,這是因?yàn)榱骺赡転榭铡?/li>
  • find查找方法:包括findFirst婚陪,findAny等。
  • match方法:根據(jù)條件查找是否有匹配條件的元素频祝,有anyMatch泌参,allMatch和noneMatch,返回的是boolean類型常空。
  • 消費(fèi)流:通過方法消費(fèi)流中的元素沽一,例如使用forEach迭代,傳遞方法處理流中的每個元素漓糙。
  • 轉(zhuǎn)換為Collection或數(shù)組:通過collect方法傳遞Collectors類提供的toCollection方法可以轉(zhuǎn)換為Collection或者調(diào)用toArray方法轉(zhuǎn)換為數(shù)組铣缠。
  • 拼接:使用Collectors.join方法可以拼接流.
  • 統(tǒng)計,使用IntSummaryStatistics昆禽、DoubleSummaryStatistics和LongSummaryStatistics方法構(gòu)造統(tǒng)計對象蝗蛙,獲取 總數(shù),平均值醉鳖,最大值捡硅,最小值。需要注意調(diào)用Collectors.summarizing{Int,Double, Long}方法需要傳遞一個lambda表達(dá)式盗棵,確定統(tǒng)計的內(nèi)容壮韭。
//獲取單詞的數(shù)量
long wordsCount = Pattern.compile("\\PL+").splitAsStream(sentences).filter(s -> s.length() > 2).count();
System.out.println("Number of words length greater than 2: " + wordsCount);

//獲取最長的單詞
Optional<String> longestWord = Pattern.compile("\\PL+").splitAsStream(sentences).max(Comparator.comparing(String::length));
System.out.println("longestWord: " + longestWord.orElse("null"));

//獲取最短的單詞
Optional<String> shortestWord = Pattern.compile("\\PL+").splitAsStream(sentences).min(Comparator.comparing(String::length));
System.out.println("shortestWord: " + shortestWord.orElse("null"));

//獲取第一個以h開頭的單詞
Optional<String> firstWordsStartWithH = Pattern.compile("\\PL+").splitAsStream(sentences)
                .filter(s -> s.toLowerCase().startsWith("h")).findFirst();
System.out.println("firstWordsStartWithH: " + firstWordsStartWithH.orElse("Not Found"));

//獲取任何一個以h開頭的單詞
Optional<String> anyWordsStartWithH = Pattern.compile("\\PL+").splitAsStream(sentences)
                .filter(s -> s.toLowerCase().startsWith("h")).findAny();
System.out.println("anyWordsStartWithH: " + anyWordsStartWithH.orElse("Not Found"));

//查找其中是否有was這個單詞
boolean hasWas = Pattern.compile("\\PL+").splitAsStream(sentences).anyMatch("was"::equals);
System.out.println("hasWas: " + hasWas);

//查找其中全部是was這個單詞
boolean allWas = Pattern.compile("\\PL+").splitAsStream(sentences).allMatch("was"::equals);
System.out.println("allWas: " + allWas);

//使用forEach方法打印全部單詞的大寫
Pattern.compile("\\PL+").splitAsStream(sentences).map(String::toUpperCase).forEach(System.out::print);

//將流轉(zhuǎn)為Collection
List<String> wordsList = Pattern.compile("\\PL+").splitAsStream(sentences).collect(Collectors.toList());
System.out.println("wordsList: " + wordsList);

//將流轉(zhuǎn)為數(shù)組
String[] wordsArray = Pattern.compile("\\PL+").splitAsStream(sentences).toArray(String[]::new);
System.out.println("wordsArray: " + Arrays.toString(wordsArray));

//將流拼接為字符串
String wordsToSentences = Pattern.compile("\\PL+").splitAsStream(sentences).collect(Collectors.joining(", "));
System.out.println("wordsToSentences: " + wordsToSentences);

//數(shù)據(jù)統(tǒng)計:統(tǒng)計單詞的長度
IntSummaryStatistics lengthSummary = Pattern.compile("\\PL+").splitAsStream(sentences).
                collect(Collectors.summarizingInt(String::length));
System.out.println("Longest word length: " + lengthSummary.getMax());
System.out.println("Shortest word length: " + lengthSummary.getMin());
System.out.println("Average word length: " + lengthSummary.getAverage());
  • 收集到Map:使用Collectors.toMap轉(zhuǎn)到Map數(shù)據(jù)中。
  • 分組:使用groupingBy進(jìn)行分組
    public static class User {
        private String name;
        private int id;
        //1=male, 0 = female, 2= unknown
        private int sex = 2;

        public User(int id, String name, int sex) {
            this.id = id;
            this.name = name;
            if (sex == 0 || sex == 1) {
                this.sex = sex;
            }
        }

        public int getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public int getSex() {
            return sex;
        }

        @Override
        public String toString() {
            return "User{id = " + id + ", name = " + name + ", sex = " + sex + "}";
        }
    }

    //省略部分代碼...

    public static Stream<User> userStream() {
        return Stream.of(
                new User(1, "Box", 1),
                new User(2, "Succi", 0),
                new User(3, "Lily", 0),
                new User(4, "Sara", 0),
                new User(5, "Mark", 1)
        );
    }
    

    //main方法
    public static void main(String[] args) {
        //...
        //映射為id -> User格式
        Map<Integer, User> userMap = userStream().collect(Collectors.toMap(User::getId, Function.identity()));
        for (Integer key:userMap.keySet()) {
            System.out.println("id " + key + ": " + userMap.get(key));
        }
        
        //映射為id -> User.name格式
        Map<Integer, String> idToNameMap = userStream().collect(Collectors.toMap(User::getId, User::getName));
        System.out.println(idToNameMap);
        
        //按性別分組
        Map<Integer, Set<User>> sexToUserMap = userStream().collect(Collectors.groupingBy(User::getSex, Collectors.toSet()));
        for (Integer key:sexToUserMap.keySet()) {
            Set<User> usersOfSex = sexToUserMap.get(key);
            System.out.println("Sex " + key + ": " + usersOfSex);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纹因,一起剝皮案震驚了整個濱河市喷屋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辐怕,老刑警劉巖逼蒙,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異寄疏,居然都是意外死亡是牢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門陕截,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驳棱,“玉大人,你說我怎么就攤上這事农曲∩缃粒” “怎么了驻债?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長形葬。 經(jīng)常有香客問我合呐,道長,這世上最難降的妖魔是什么笙以? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任淌实,我火速辦了婚禮,結(jié)果婚禮上猖腕,老公的妹妹穿的比我還像新娘拆祈。我一直安慰自己,他們只是感情好倘感,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布放坏。 她就那樣靜靜地躺著,像睡著了一般老玛。 火紅的嫁衣襯著肌膚如雪淤年。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天逻炊,我揣著相機(jī)與錄音互亮,去河邊找鬼。 笑死余素,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炊昆。 我是一名探鬼主播桨吊,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凤巨!你這毒婦竟也來了视乐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤敢茁,失蹤者是張志新(化名)和其女友劉穎佑淀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體彰檬,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伸刃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逢倍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捧颅。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖较雕,靈堂內(nèi)的尸體忽然破棺而出碉哑,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布扣典,位于F島的核電站妆毕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贮尖。R本人自食惡果不足惜设塔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望远舅。 院中可真熱鬧闰蛔,春花似錦、人聲如沸图柏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚤吹。三九已至例诀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間裁着,已是汗流浹背繁涂。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留二驰,地道東北人扔罪。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像桶雀,于是被迫代替她去往敵國和親矿酵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359