List轉Map思想的妙用

       最近做項目,遇到了很多雙層for循環組裝數據的情況,有的甚至是三層循環,數據組裝比較麻煩,同事看到我有一個三層的for循環,說你這個可以優化成兩層,三層嵌套的太深了,數據量大的情況下,性能會比較差。是的,大家都知道for循環嵌套的越深,數據量大的情況下,循環遍歷的次數也是成指數級增長的,性能可想而知(雖然當時我做的這個項目的數據量只有幾百,沒有太大,這也是當時編碼的時候直接用了三層for循環的原因,後來還是聽從了同事的意見,優化了一波)。雖然當時我知道數據量不是很大,但是作爲一個技術人,有可以改進的地方,堅決不能放過任何可以優化的點,這是作爲技術人的底線,也是對高質量代碼的追求,盡力保證自己寫出來的代碼都是高效,安全,快速的。後來從這個優化中我體會到了List轉Map思想的妙用,性能成幾何倍數增加,後來自己又拓展到兩層for循環,做了一些測試,發現確實妙不可言,雖然只是一個小小的優化,我覺得有必要記錄下來,分享一下自己的心得,方便大家共同學習。廢話說了這麼多,現在我帶大家一步一步的演示,先看一下雙層for循環下的性能測試數據:

 public static Map<String, AllUserInfoModel> getTeamBdmMap(List<AllUserInfoModel> allUserInfoModelList, List<Integer> allBdm) {
        Map<String, AllUserInfoModel> teamBdmMap = new HashMap<>(128);
        allBdm.forEach(item -> {
            allUserInfoModelList.forEach(user -> {
                if (item.equals(user.getSysUserId())) {
                    if (StringUtils.isNotBlank(user.getDepartmentName())) {
                        teamBdmMap.put(user.getDepartmentName(), user);
                    }
                }
            });
        });
        return teamBdmMap;
    }

public static void main(String[] args) {
        List<AllUserInfoModel> allUserInfoModelList = new ArrayList<>();
        List<Integer> allBdm = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            AllUserInfoModel userInfoModel = new AllUserInfoModel();
            userInfoModel.setSysUserId(i);
            userInfoModel.setDepartmentName("測試戰隊-" + i);
            allUserInfoModelList.add(userInfoModel);
            if (i % 100 == 0) {
                allBdm.add(i);
            }
        }
        long ls = System.currentTimeMillis();
        getTeamBdmMap(allUserInfoModelList, allBdm);
        long le = System.currentTimeMillis();
        System.out.println(le - ls);
    }

測試十萬次的結果爲:

以上是我們按照一般的正常List循環兩層遍歷得到的結果,2543毫秒即2.5s。

下面讓我們看一下轉map後的測試結果:

public static Map<String, AllUserInfoModel> getTeamBdmMapTest(List<AllUserInfoModel> allUserInfoModelList, List<Integer> allBdm) {
        Map<String, AllUserInfoModel> teamBdmMap = new HashMap<>(128);
        Map<Integer, AllUserInfoModel> userMap = allUserInfoModelList.stream().collect(Collectors.toMap(AllUserInfoModel::getSysUserId, user -> user));
        allBdm.forEach(item -> {
            AllUserInfoModel user = userMap.get(item);
            if (Objects.nonNull(user) && StringUtils.isNotBlank(user.getDepartmentName())) {
                teamBdmMap.put(user.getDepartmentName(), user);
            }
        });
        return teamBdmMap;
    }

    public static void main(String[] args) {
        List<AllUserInfoModel> allUserInfoModelList = new ArrayList<>();
        List<Integer> allBdm = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            AllUserInfoModel userInfoModel = new AllUserInfoModel();
            userInfoModel.setSysUserId(i);
            userInfoModel.setDepartmentName("測試戰隊-" + i);
            allUserInfoModelList.add(userInfoModel);
            if (i % 100 == 0) {
                allBdm.add(i);
            }
        }
        long ls2 = System.currentTimeMillis();
        getTeamBdmMapTest(allUserInfoModelList, allBdm);
        long le2 = System.currentTimeMillis();
        System.out.println(le2 - ls2);
    }

轉Map後測試十萬次的結果如下:

把allUserInfoModelList轉爲Map<Integer, AllUserInfoModel> userMap後時間爲137毫秒即爲0.1秒,兩次結果做個對比可以發現後者比前者提高了約250倍的性能,如果更大的數據量,性能更是指數級提升。正是利用了Map的快速查找(算法複雜度O(1)),減少了循環遍歷的次數(時間複雜度由O(n)轉變爲了O(1)),性能才得以百倍提升(不過增加了空間複雜度,此處是空間換時間,需要在內存不緊張的條件下進行,需要結合實際情況選取是否需要轉換)。我覺得這是一種思路的轉變,只是一個小小的轉換,性能卻是天差地別,當然,這個要看具體的業務場景,也不能一味的爲了用map而用map,根據具體的業務場景需求,選擇合適的方法纔是最好的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章