1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        相信我,使用 Stream 真的可以讓代碼更優(yōu)雅!

        共 8152字,需瀏覽 17分鐘

         ·

        2022-05-26 16:33


        點(diǎn)擊關(guān)注公眾號:互聯(lián)網(wǎng)架構(gòu)師,后臺回復(fù) 2T獲取2TB學(xué)習(xí)資源!

        上一篇:Alibaba開源內(nèi)網(wǎng)高并發(fā)編程手冊.pdf

        原文:blog.csdn.net/qq_41698074/article/details/108502976


        前言

        雖然 stream在 Java8 中就已經(jīng)被引入,但是大多數(shù)人卻沒有去使用這個(gè)十分有用的特性,本文就通過介紹幾個(gè)通過使用stream讓代碼更簡潔、可讀,來讓你了解stream的方便之處。

        技巧

        數(shù)組轉(zhuǎn)集合

        相信經(jīng)常刷LeetCode的小伙伴,偶爾會遇到需要將List與基本類型數(shù)組進(jìn)行互轉(zhuǎn)的情況,然后就需要寫像下面這樣的代碼:

        // 將 List 元素存儲到數(shù)組中
        List<Integer> list = new ArrayList<>(Arrays.asList(12345));
        int[] arr = new int[list.size()];
        Integer[] temp = list.toArray(new Integer[0]);
        for (int i = 0; i < temp.length; i++) {
         arr[i] = temp[i];
        }

        // 將數(shù)組元素 存儲到 List 中
        int[] arr = {12345};
        List<Integer> list = new ArrayList<>();
        for (int val : arr) {
         list.add(val);
        }

        以上兩個(gè)轉(zhuǎn)換雖然寫著還不算麻煩,但是每次都需要寫一個(gè)循環(huán),尤其在數(shù)組轉(zhuǎn)List的時(shí)候還需要使用一個(gè)臨時(shí)數(shù)組,都會讓人看著很不舒服,但是如果使用了stream就會大不一樣,用stream實(shí)現(xiàn)了相同功能的代碼如下:

        // 將 List 元素存儲到數(shù)組中
        List<Integer> list = new ArrayList<>(Arrays.asList(12345));
        int[] arr = list.stream().mapToInt(Integer::intValue).toArray();

        // 將數(shù)組元素 存儲到 List 中
        int[] arr = {12345};
        List<Integer> list = IntStream.of(arr).boxed().collect(Collectors.toList());

        可以發(fā)現(xiàn)通過使用stream,我們能夠在寫代碼的時(shí)候更加連貫,代碼也更加可靠易維護(hù),注意力也可以放在業(yè)務(wù)功能上,相信各位就算對lambda語法并不是太熟悉,在閱讀上面代碼的時(shí)候,也很容易能夠看懂。

        統(tǒng)計(jì)數(shù)組元素中的個(gè)數(shù)

        假設(shè)我們現(xiàn)在需要統(tǒng)計(jì)并輸出一個(gè)有重復(fù)元素的數(shù)組中每個(gè)元素及對應(yīng)元素出現(xiàn)的個(gè)數(shù),相信各位都能夠想到,我們使用一個(gè)Map就很容易解決這個(gè)問題,代碼如下:

        String[] arr = {"a""c""a""b""d""c"};
        Map<String, Integer> map = new HashMap<>();
        for (String s : arr) {
            if (map.containsKey(s)) {
                map.put(s, map.get(s) + 1);
            } else {
                map.put(s, 1);
            }
        }
        map.forEach((key, value) -> System.out.println(key + " : " + value));

        如果對Map中的API更加熟悉的小伙伴,可能會寫出下面這個(gè)更加簡潔的代碼:

        String[] arr = {"a""c""a""b""d""c"};
        Map<String, Integer> map = new HashMap<>();
        for (String s : arr) {
            map.put(s, map.getOrDefault(s, 0) + 1);
        }
        map.forEach((key, value) -> System.out.println(key + " : " + value));

        但是,如果使用stream,我們還能寫出更加簡潔的代碼,同樣不需要寫煩人的循環(huán)了,而且只需兩行代碼即可(為了提高可讀性,進(jìn)行了換行):

        String[] arr = {"a""c""a""b""d""c"};
        Stream.of(arr)
              .collect(Collectors.toMap(k -> k, k -> 1, Integer::sum))
              .forEach((k, v) -> System.out.println(k + " : " + v));
        注意

        在上面的代碼中,Collectors.toMap(k -> k, k -> 1, Integer::sum)這一部分可能不好理解,對于這里面的三個(gè)參數(shù),第一個(gè)參數(shù)代表將arr中的每一個(gè)元素作為Map中的key,第二個(gè)參數(shù)代表每一個(gè)key所對應(yīng)的value,在這里每一個(gè)元素都對應(yīng)個(gè)數(shù)1,第三個(gè)參數(shù)代表,如果存在相同的key,該如何進(jìn)行合并,這里通過使用Integer::sum,代表將具有相同key的元素進(jìn)行合并時(shí),其value進(jìn)行相加,這樣便實(shí)現(xiàn)了每個(gè)元素個(gè)數(shù)的統(tǒng)計(jì)。

        基本數(shù)據(jù)類型的數(shù)組自定義排序

        有時(shí)我們會遇到對基本數(shù)據(jù)類型的數(shù)組進(jìn)行自定義排序的情況,不同于包裝類型的數(shù)組和集合可以直接使用比較器,我們只能通過將基本數(shù)組類型的數(shù)組轉(zhuǎn)為包裝類型或者存儲在集合中,在排序完成后再轉(zhuǎn)為基本類型的數(shù)組,再者,我們只能通過手寫排序算法,修改排序算法中的比較進(jìn)行實(shí)現(xiàn)。

        不管是哪種方法,我們都沒辦法將精力放在邏輯功能上,必須寫一些額外的代碼,甚至是修改底層邏輯,就像下面的代碼一樣(實(shí)現(xiàn)數(shù)組逆序):

        int[] arr = {1597237, -103};
        // 將數(shù)組轉(zhuǎn)為包裝類型再進(jìn)行自定義排序
        Integer[] temp = new Integer[arr.length];
        for (int i = 0; i < arr.length; i++) {
            temp[i] = arr[i];
        }
        Arrays.sort(temp, Comparator.reverseOrder());
        for (int i = 0; i < temp.length; i++) {
            arr[i] = temp[i];
        }

        // 將數(shù)組轉(zhuǎn)為集合類型再進(jìn)行自定義排序
        List<Integer> list = new ArrayList<>();
        for (int val : arr) {
            list.add(val);
        }
        list.sort(Collections.reverseOrder());
        for (int i = 0; i < list.size(); i++) {
            arr[i] = list.get(i);
        }

        // 通過手寫排序算法修改比較規(guī)則實(shí)現(xiàn)
        // 為了讓代碼更加簡潔,使用了最暴力且沒有優(yōu)化的冒泡排序
        int[] arr = {1597237, -103};
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] < arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }

        可以發(fā)現(xiàn)以上幾種方法,我們都需要寫很多代碼,無法將注意力集中在設(shè)計(jì)自定義排序這個(gè)問題上,但是通過使用stream,我們就可以寫出下面這樣簡潔的代碼(如果愿意的話,你也可以把一系列的鏈?zhǔn)讲僮鲗懺谝恍猩希珵榱舜a的可讀性,不建議那么做):

        int[] arr = {1597237, -103};
        arr = IntStream.of(arr)
                       .boxed()
                       .sorted(Comparator.reverseOrder())
                       .mapToInt(Integer::intValue)
                       .toArray();
        注意

        在這里其實(shí)為了實(shí)現(xiàn)數(shù)組的逆序,我們只需要調(diào)用Arrays的sort方法,然后再進(jìn)行數(shù)組元素的反轉(zhuǎn)即可,不過因?yàn)槭菫榱酥v解自定義排序,大多數(shù)情況下不會是數(shù)組逆序這么簡單,所以我就寫了更加通用一些的代碼。

        統(tǒng)計(jì)數(shù)組中前 k 個(gè)個(gè)高頻元素

        在最后,我們通過一道題來進(jìn)行實(shí)戰(zhàn)以便更好的體驗(yàn)stream的強(qiáng)大之處,當(dāng)然我們在練習(xí)該題的時(shí)候,更需要從算法的角度去考慮該題的解法,不過在本文,我們主要為了講解stream的使用,所以就不去考慮算法的東西了,而如果使用stream,我們就可以寫出下面這樣簡單易懂的代碼:

        class Solution {
            public int[] topKFrequent(int[] nums, int k) {
                return Arrays.stream(nums)
                             .boxed()
                             .collect(Collectors.toMap(e -> e, e -> 1, Integer::sum))
                             .entrySet()
                             .stream()
                             .sorted((m1, m2) -> m2.getValue() - m1.getValue())
                             .limit(k)
                             .mapToInt(Map.Entry::getKey)
                             .toArray();
            }
        }

        總結(jié)

        本文介紹了幾個(gè)簡單、實(shí)用的stream使用技巧,當(dāng)然stream的應(yīng)用遠(yuǎn)不止此,希望通過本文,能夠激發(fā)起你學(xué)習(xí)stream的興趣,本文若有錯(cuò)誤之處,也歡迎你的指正。


        -End-
        最后,關(guān)注公眾號互聯(lián)網(wǎng)架構(gòu)師,在后臺回復(fù):2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全


        正文結(jié)束


        推薦閱讀 ↓↓↓

        1.心態(tài)崩了!稅前2萬4,到手1萬4,年終獎(jiǎng)扣稅方式1月1日起施行~

        2.深圳一普通中學(xué)老師工資單曝光,秒殺程序員,網(wǎng)友:敢問是哪個(gè)學(xué)校畢業(yè)的?

        3.從零開始搭建創(chuàng)業(yè)公司后臺技術(shù)棧

        4.程序員一般可以從什么平臺接私活?

        5.清華大學(xué):2021 元宇宙研究報(bào)告!

        6.為什么國內(nèi) 996 干不過國外的 955呢?

        7.這封“領(lǐng)導(dǎo)痛批95后下屬”的郵件,句句扎心!

        8.15張圖看懂瞎忙和高效的區(qū)別!

        瀏覽 34
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品久久久久网站 | 日本人Japanese人妖 | 人人色人人摸 | 精品一区二区三区四区视频 | 天天综合视频 中文字幕 | 国产操逼图 | 一级内射视频 | 99久久99久久免费精品蜜臀 | 精品国产乱码久久久久夜深人妻 | 91熟女半推半就对了白在线 |