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的快速查找,减少了循环遍历的次数,性能才得以百倍提升。我觉得这是一种思路的转变,只是一个小小的转换,性能却是天差地别,当然,这个要看具体的业务场景,也不能一味的为了用map而用map,根据具体的业务场景需求,选择合适的方法才是最好的。