避免双重for循环寻找相同条件拖慢查询速度
开发中我们会遇到以下这种场景:
我们通过查询条件,查询出两个不同实体的 list ,这两个实体通过一个外键id相关联,这时候我们要返回的这个实体中需要对应的另一个实体中的某一项值,这时候传统的思路是什么样的
List<A> bigA=new ArraryList();
List<B> bigB=new ArraryList();
for(A aa : bigA){
for(B bb : bigB){
if(aa.getInfoId().equals(bb.getInfoId()){
//如果是单项值 1对1 的操作
aa.setForValue(bb.getForValue())
//如果是多项值 1对多 的情况
aa.setForValue( aa.getForValue + bb.getForValue );
}
}
}
return bigA;
存在问题
这样会存在大量的 for 循环存在,如果数据很少,则没有什么问题,但是当数据量多起来之后,这个接口很容易堵在这里,这还只是一个查找对应并进行取值和赋值,如果在循环中还有对数据库的查询操作那么就不止接口时间长的问题了,还会对数据库造成负担。
解决方法
为了避免大量的 for 循环存在,我们首先将外层 for 循环改成 stream 形式进行循环,这时候,内层肯定不能也只改成 stream 流的方式,这样双重循环并没有解决,这时候我们有两种情况
1.对比的这个 InfoId 对于 List 来说是唯一的,也就是单项值,1 对 1 的情况,那么这时候
//假设这个list
List<InfoResponse> infoList=...list的获取过程...
Map<Long, InfoResponse> resultMap = infoList.stream()
.filter(item -> item.getInfoId() != null)
.collect(Collectors.toMap(InfoResponse::getInfoId, data -> data));
如果你在这个id之下还有查询也可以
Map<Long, InfoResponse> resultMap = infoList.stream()
.collect(Collectors.toMap(InfoResponse::getInfoId, entity -> {
return mapper.selectById(entity.getId());
}));
这样将list转化为 Map 之后,再进行另一个 list 的 for 循环时,就可以避免一次循环嵌套,例如
//另一个list,假设是个AInfoEntities 的list
List<AInfoEntities> aInfoEntities = ...
AInfoEntities result = aInfoEntities.stream().map(item -> {
InfoResponse infoResponse= resultMap.get(item.getInfoId());
item.setNewData(Objects.isNull(infoResponse) ? "0" : infoResponse.getNewData());
return item;
}).collect(Collectors.toList());
这样你就可以将第一个 list 其中的某项值根据 InfoId 设置进第一个 list ,并返回想要的 list 结果;
2. 对比的这个infoId 不是唯一值,在第二个list中存在多个的时候,也就是多项值的情况
Map<Long,List<InfoResponse>> resultMap = infoList.stream().collect(Collectors.groupingBy(InfoResponse::getInfoId));
或者如果你是只要知道map中key值对应的list的size的话
Map<Long,Long> resultMap = infoList.stream().collect(Collectors.groupingBy(InfoResponse::getInfoId,Collectors.counting()));
这样转化成map之后,再进行另一个list的循环赋值
//另一个list,假设是个AInfoEntities 的list
List<AInfoEntities> aInfoEntities = ...
AInfoEntities result = aInfoEntities.stream().map(item -> {
List<InfoResponse> infoResponseList= resultMap.get(item.getInfoId());
//直接list赋值
item.setSonList(infoResponseList);
//或者对list的操作
Long count = infoResponseList.stream().filter(item-> item.getStatus() == 2).count();
item.setNewDate(count);
return item;
}).collect(Collectors.toList());
这样我们就通过对其中一个list转化为map的操作,将双重for循环打破,变成单循环,单循环我们又通过使用stream流进行操作,如果你的单循环中只会有一个符合,还可以使用增加 break 的方法。
本人Java小白新手,如有不妥,还望包涵指正,谢谢!