java8出来了好多年,好多特性一直收益至今,真的太强大了
我今天要说的是stream groupingBy 使用案例,喜欢的朋友可以借鉴
如果熟练使用了groupingBy 方式,每次写代码,至少可以将20行代码变为1行,也许有人说,这怎么可能?我告诉你,没有什么不可能的,今天我就告诉你如何将20行的代码,变为1行代码
背景:项目中需要做一个从第三方同步角色的功能,角色上有分类,也就是角色组,获取角色的接口和获取角色组的接口是分开的,同步过来的角色和角色组写到数据库时,都会各自生产自身系统的id,当然也会记录同步过来的数据id的关系,这样才能保证是同一条数据的更新。系统中的角色和角色组的关系,是用系统的id做的关联,因此,从第三方获取到角色数据后,需要根据第三方角色所属角色组id,找到系统中的角色组,再写入到数据库
直接撸代码,初始版本:
Map<String,List<RoleConfInfoVO>>cateInfos=new HashMap<>();
for (RoleConfInfoVO roleConfInfoVO:roleConfInfoVOS){
if(StringUtils.isNotEmpty(roleConfInfoVO.getRoleConfCateId())){
if(cateInfos.containsKey(roleConfInfoVO.getRoleConfCateId())){
List<RoleConfInfoVO> infoVOList = cateInfos.get(roleConfInfoVO.getRoleConfCateId());
infoVOList.add(roleConfInfoVO);
}else {
List<RoleConfInfoVO>infoVOList=Lists.newArrayList();
infoVOList.add(roleConfInfoVO);
cateInfos.put(roleConfInfoVO.getRoleConfCateId(),infoVOList);
}
}else {
//默认分组
if(cateInfos.containsKey(defaultGroupSourceId)){
List<RoleConfInfoVO> infoVOList = cateInfos.get(defaultGroupSourceId);
infoVOList.add(roleConfInfoVO);
}else {
List<RoleConfInfoVO>infoVOList=Lists.newArrayList();
infoVOList.add(roleConfInfoVO);
cateInfos.put(defaultGroupSourceId,infoVOList);
}
}
}
说明:
- cateInfo 对象是一个map集合,key是第三方角色组id,value是角色组下的所有角色集合
- for循环遍历角色数据,将其按角色组id进行分类,如果已经cateInfo 中已经存在了key,则取出value,将角色添加到list里面
首先说明下,为什么要这样循环去分类,原因是这样,从第三方获取到的角色可能有几万个,如果不进行分类,直接循环遍历第三方角色列表,再根据角色的分类去本地数据库查找角色组,那就要查询角色组几万次数据库,会比较耗性能。如果按分类分号后,再循环遍历cateInfo map集合元素去查询,一般只有几个角色组,也就是原本只需要查询几万次数据库的,现在只需要查询几次就可以了,性能大大提升了。
好了,到这里,上述代码对角色按第三方角色组id的方式分组了,看似代码没啥问题,确实也没啥问题,只是代码量多了
不经意间我想起来了java8的新特性stream groupingBy 的使用,可以通过这个特性,用很少的代码量,就可以轻松的将一个集合对象按某个字段进行分类
于是,上代码:
Map<String, List<RoleConfInfoVO>> cateInfos = roleConfInfoVOS.stream().collect(Collectors.groupingBy(g -> StringUtils.isEmpty(g.getRoleConfCateId())?defaultGroupSourceId:g.getRoleConfCateId()));
代码量,一行足以
这就是java8新特性带来的便利,为我们程序猿节省了不少代码,程序也更加简洁
事实上,Collectors.groupingBy根据一个或多个属性对集合中的项目进行分组
1.如果需要多个属性进行分组,可以将多个属性拼接分组
Map<String, List<Product>> prodMap = prodList.stream().collect(Collectors.groupingBy(item -> item.getCategory() + "_" + item.getName()));
大家可以根据分组情况自行选择分组需求
2.求总数
Map<String, Long> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.counting()));
3.求和
Map<String, Integer> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.summingInt(Product::getNum)));
等等,使用方式有很多,在这里举例这几种,其他需要根据实际场景去使用了