List转Map思想的妙用

       最近做项目,遇到了很多双层for循环组装数据的情况,有的甚至是三层循环,数据组装比较麻烦,同事看到我有一个三层的for循环,说你这个可以优化成两层,三层嵌套的太深了,数据量大的情况下,性能会比较差。是的,大家都知道for循环嵌套的越深,数据量大的情况下,循环遍历的次数也是成指数级增长的,性能可想而知(虽然当时我做的这个项目的数据量只有几百,没有太大,这也是当时编码的时候直接用了三层for循环的原因,后来还是听从了同事的意见,优化了一波)。虽然当时我知道数据量不是很大,但是作为一个技术人,有可以改进的地方,坚决不能放过任何可以优化的点,这是作为技术人的底线,也是对高质量代码的追求,尽力保证自己写出来的代码都是高效,安全,快速的。后来从这个优化中我体会到了List转Map思想的妙用,性能成几何倍数增加,后来自己又拓展到两层for循环,做了一些测试,发现确实妙不可言,虽然只是一个小小的优化,我觉得有必要记录下来,分享一下自己的心得,方便大家共同学习。废话说了这么多,现在我带大家一步一步的演示,先看一下双层for循环下的性能测试数据:

 public static Map getTeamBdmMap(List allUserInfoModelList, List allBdm) {
        Map 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 allUserInfoModelList = new ArrayList<>();
        List 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转Map思想的妙用_第1张图片

以上是我们按照一般的正常List循环两层遍历得到的结果,2543毫秒即2.5s。

下面让我们看一下转map后的测试结果:

public static Map getTeamBdmMapTest(List allUserInfoModelList, List allBdm) {
        Map teamBdmMap = new HashMap<>(128);
        Map 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 allUserInfoModelList = new ArrayList<>();
        List 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后测试十万次的结果如下:

List转Map思想的妙用_第2张图片

把allUserInfoModelList转为Map userMap后时间为137毫秒即为0.1秒,两次结果做个对比可以发现后者比前者提高了约250倍的性能,如果更大的数据量,性能更是指数级提升。正是利用了Map的快速查找(算法复杂度O(1)),减少了循环遍历的次数(时间复杂度由O(n)转变为了O(1)),性能才得以百倍提升(不过增加了空间复杂度,此处是空间换时间,需要在内存不紧张的条件下进行,需要结合实际情况选取是否需要转换)。我觉得这是一种思路的转变,只是一个小小的转换,性能却是天差地别,当然,这个要看具体的业务场景,也不能一味的为了用map而用map,根据具体的业务场景需求,选择合适的方法才是最好的。

你可能感兴趣的:(编程思想篇)