1、使用Stream流进行合并
public List<IndustryResultDto> findTest(Long industryChainId, String level) {
List<IndustryResultDto> flow = findAmountFlowByLevel( industryChainId, "流入", level,"0" );
List<IndustryResultDto> out = findAmountFlowByLevel( industryChainId, "流出", level,"0" );
return Stream.concat(
Optional.ofNullable(flow).map(List::stream).orElseGet(Stream::empty),
Optional.ofNullable(out).map(List::stream).orElseGet(Stream::empty)
)
.collect(Collectors.toMap(
IndustryResultDto::getIndustryId,
Function.identity(),
(existing, newValue) -> {
IndustryResultDto result = new IndustryResultDto();
result.setIndustryId(existing.getIndustryId());
result.setResult(Optional.ofNullable(existing.getResult()).orElse(BigDecimal.ZERO)
.subtract(Optional.ofNullable(newValue.getResult()).orElse(BigDecimal.ZERO)));
return result;
}
))
.values()
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
相关代码解释
这个方法 findTest计算并返回一个包含 IndustryResultDto 对象的列表。列表中的每个对象代表一个行业的净流量(流入量减去流出量)。
下面详细解释每一步骤:
1、获取流入和流出数据:
List<IndustryResultDto> flow = findAmountFlowByLevel(industryChainId, "流入", level, "0");
List<IndustryResultDto> out = findAmountFlowByLevel(industryChainId, "流出", level, "0");
使用 findAmountFlowByLevel 方法分别获取指定产业链 ID 和层级的流入和流出数据。这两个列表 flow 和 out 存储了对应的 IndustryResultDto 对象。
2、合并流入和流出数据:
return Stream.concat(
Optional.ofNullable(flow).map(List::stream).orElseGet(Stream::empty),
Optional.ofNullable(out).map(List::stream).orElseGet(Stream::empty)
)
使用 Stream.concat 将 flow 和 out 两个流合并。如果 flow 或 out 为空,则使用 Stream::empty 创建一个空流。
3、创建 ID 到 IndustryResultDto 的映射:
.collect(Collectors.toMap(
IndustryResultDto::getIndustryId, // key: 使用 IndustryResultDto 的 industryId
Function.identity(), // value: 直接使用 IndustryResultDto 对象
(existing, newValue) -> { // 如果 key 冲突时执行的合并逻辑
IndustryResultDto result = new IndustryResultDto();
result.setIndustryId(existing.getIndustryId());
result.setResult(
Optional.ofNullable(existing.getResult()).orElse(BigDecimal.ZERO)
.subtract(Optional.ofNullable(newValue.getResult()).orElse(BigDecimal.ZERO))
);
return result;
}
1、toMap 参数解释:
keyMapper (IndustryResultDto::getIndustryId): 使用 IndustryResultDto 的 industryId 作为键。
valueMapper (Function.identity()): 直接使用 IndustryResultDto 对象作为值。
mergeFunction: 当键冲突(即同一个 industryId 多次出现)时,使用合并函数来处理冲突。
))
2、合并函数:
(existing, newValue) -> {
IndustryResultDto result = new IndustryResultDto();
result.setIndustryId(existing.getIndustryId()); // 设置 industryId
// 计算 result 的值
result.setResult(
Optional.ofNullable(existing.getResult()).orElse(BigDecimal.ZERO) // 取 existing 的 result,如果为 null 则用 BigDecimal.ZERO
.subtract(Optional.ofNullable(newValue.getResult()).orElse(BigDecimal.ZERO)) // 减去 newValue 的 result,如果为 null 则用 BigDecimal.ZERO
);
return result; // 返回新的 IndustryResultDto 对象
}
合并逻辑的工作原理
当 existing 和 newValue 都有相同的 industryId 时:
创建一个新的 IndustryResultDto 对象 result。
设置 result 的 industryId 为 existing 的 industryId。
计算 result 的 result 值:
取 existing 的 result 值,如果为 null 则使用 BigDecimal.ZERO。
取 newValue 的 result 值,如果为 null 则使用 BigDecimal.ZERO。
用 existing 的 result 值减去 newValue 的 result 值。
返回新的 result 对象。
将合并后的流收集成一个 Map,其中 key 是 IndustryResultDto 的 industryId,value 是 IndustryResultDto 对象。若同一个 industryId 有多个值,则执行合并逻辑:
创建一个新的 IndustryResultDto 对象 result。
设置其 industryId。
计算 result 值:existing 的 result 减去 newValue 的 result。如果 result 为 null,则默认使用 BigDecimal.ZERO。
4、提取 Map 中的值并过滤非空值:
.values().stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
这一步骤将 Map 中的所有值(IndustryResultDto 对象)转换为流,并过滤掉所有的 null 值,最后收集到一个列表中。
综上所述,整个方法 findAmountFlowSubtractByLevel 的主要目的是计算每个产业的净流量,并返回一个非空的 IndustryResultDto 列表。每个 IndustryResultDto 对象包含产业 ID 和净流量(流入减去流出)
2、使用for循环方式
public List<DistrictResultDto> techTest(Long industryChainId) {
Map<String, Map<String,Object>> patentAndCopiesMap = baseMapper.getPatentAndCopiesByArea(industryChainId);
Map<String, Map<String,Object>> allCompanymap = baseMapper.getAllCompanyByArea(industryChainId);
List<DistrictResultDto> districtResultDtoList = new ArrayList<>();
Set<String> allCompanyKeys = new HashSet<>(allCompanymap.keySet());
for (String allCompanyKey : allCompanyKeys) {
DistrictResultDto districtResultDto = new DistrictResultDto();
districtResultDto.setDistrict(allCompanyKey);
Map<String, Object> allCompany = allCompanymap.get(allCompanyKey);
if (0L == Long.parseLong( MapUtil.getStr(allCompany, "result"))){
districtResultDto.setResult(BigDecimal.ZERO);
}else {
Map<String, Object> patentAndCopies = patentAndCopiesMap.get(allCompanyKey);
if (null == patentAndCopies ){
districtResultDto.setResult(BigDecimal.ZERO);
}else {
Long patentAndCopiesLong = Long.parseLong(MapUtil.getStr(patentAndCopies, "result")) ;
Long allCompanyLong = Long.parseLong(MapUtil.getStr(allCompany, "result")) ;
BigDecimal result = BigDecimal.valueOf(patentAndCopiesLong/allCompanyLong);
districtResultDto.setResult(result);
}
}
districtResultDtoList.add(districtResultDto);
}
return districtResultDtoList;
}
1、获取数据:
Map<String, Map<String, Object>> patentAndCopiesMap = baseMapper.getPatentAndCopiesByArea(industryChainId);
调用 baseMapper.getPatentAndCopiesByArea 方法,根据 industryChainId 获取一个包含专利和复印件数据的 Map。这个 Map 的键是区域名,值是一个包含相关数据的 Map。
2、获取其他数据:
Map<String, Map<String, Object>> allCompanymap = baseMapper.getAllCompanyByArea(industryChainId);
调用 baseMapper.getAllCompanyByArea 方法,根据 industryChainId 获取一个包含所有公司数据的 Map。这个 Map 的键也是区域名,值是一个包含相关数据的 Map。
3、初始化结果列表和所有公司键的集合:
List<DistrictResultDto> districtResultDtoList = new ArrayList<>();
Set<String> allCompanyKeys = new HashSet<>(allCompanymap.keySet());
创建一个空的 DistrictResultDto 列表 districtResultDtoList,用于存储最终的结果。并从 allCompanymap 中获取所有区域的键,存入 allCompanyKeys 集合。
4、遍历所有公司键集合,计算每个区域的结果:
for (String allCompanyKey : allCompanyKeys) {
DistrictResultDto districtResultDto = new DistrictResultDto();
districtResultDto.setDistrict(allCompanyKey);
Map<String, Object> allCompany = allCompanymap.get(allCompanyKey);
if (0L == Long.parseLong(MapUtil.getStr(allCompany, "result"))) {
districtResultDto.setResult(BigDecimal.ZERO);
} else {
Map<String, Object> patentAndCopies = patentAndCopiesMap.get(allCompanyKey);
if (null == patentAndCopies) {
districtResultDto.setResult(BigDecimal.ZERO);
} else {
Long patentAndCopiesLong = Long.parseLong(MapUtil.getStr(patentAndCopies, "result"));
Long allCompanyLong = Long.parseLong(MapUtil.getStr(allCompany, "result"));
BigDecimal result = BigDecimal.valueOf((double) patentAndCopiesLong / allCompanyLong);
districtResultDto.setResult(result);
}
}
districtResultDtoList.add(districtResultDto);
}
遍历 allCompanyKeys 集合,对于每个区域名 allCompanyKey:
创建一个新的 DistrictResultDto 对象,并设置其 district 字段为当前区域名。
从 allCompanymap 中获取当前区域名对应的公司数据 allCompany。
检查 allCompany 中的 result 值是否为 0。如果是,设置 districtResultDto 的 result 为 BigDecimal.ZERO。
如果 result 不为 0,从 patentAndCopiesMap 中获取当前区域名对应的专利和复印件数据 patentAndCopies。如果 patentAndCopies 为 null,同样设置 result 为 BigDecimal.ZERO。
如果 patentAndCopies 不为 null,计算 patentAndCopies 中 result 与 allCompany 中 result 的比值,并设置到 districtResultDto 的 result 字段。
将 districtResultDto 添加到 districtResultDtoList 列表中。
5、返回结果列表:
return districtResultDtoList;
返回计算后的结果列表 districtResultDtoList。
总结
该方法通过从数据库中获取指定产业链 ID 对应的不同区域的数据,计算每个区域的特定结果,并将结果封装在 DistrictResultDto 对象中,最终返回一个包含所有区域计算结果的列表