如何用Stream API按关联字段合并两个对象列表
优化DTO列表匹配更新的Stream API实现
问题背景
我有两个DTO列表:
List<BigDataDto> bigDataList = [ BigDataDto(id=1, key=null, timestamp=2024-05-24 15:38:00, value=10, status=null), BigDataDto(id=2, key=null, timestamp=2024-05-24 15:38:00, value=10, status=null), BigDataDto(id=3, key=null, timestamp=2024-05-24 15:38:00, value=10, status=null) ] List<SmallDataDto> smallDataList = [ SmallDataDto(extraId=1, hmpid=a63ffce5-1d86-3afc-8b5a-97452f935632, status=ACTIVE), SmallDataDto(extraId=2, hmpid=1dbd3cd0-8382-3736-a9bd-f2cc78187dad, status=INACTIVE), SmallDataDto(extraId=3, hmpid=6ed7a21e-22a3-39a0-a83c-734e35625c67, status=DELETED) ]
需要实现:当BigDataDto.id与SmallDataDto.extraId匹配时,用SmallDataDto的hmpid更新BigDataDto.key,用SmallDataDto.status更新BigDataDto.status,最终得到更新后的列表:
List<BigDataDto> resultDataList = [ BigDataDto(id=1, key=a63ffce5-1d86-3afc-8b5a-97452f935632, timestamp=2024-05-24 15:38:00, value=10, status=ACTIVE), BigDataDto(id=2, key=1dbd3cd0-8382-3736-a9bd-f2cc78187dad, timestamp=2024-05-24 15:38:00, value=10, status=INACTIVE), BigDataDto(id=3, key=6ed7a21e-22a3-39a0-a83c-734e35625c67, timestamp=2024-05-24 15:38:00, value=10, status=DELETED) ]
现有实现
我当前的实现如下,但希望优化成更符合Stream API风格的写法:
for(BigDataDto bigData : bigDataList){ Optional<SmallDataDto> findRelated = smallDataList.stream() .filter(data -> Objects.equals(data.getExtraId(), bigData.getId())) .findFirst(); bigData.setKey(String.valueOf(findRelated.get().getHmpid())); bigData.setStatus(String.valueOf(findRelated.get().getStatus())); }
优化后的Stream风格实现
方案1:修改原列表(高效版)
先将smallDataList转为以extraId为键的Map,避免重复遍历查找,再用Stream处理更新:
// 转换为Map,提升匹配查找效率 Map<Integer, SmallDataDto> smallDataMap = smallDataList.stream() .collect(Collectors.toMap(SmallDataDto::getExtraId, dto -> dto)); // 用Stream遍历更新bigDataList bigDataList.stream() .forEach(bigData -> { SmallDataDto smallData = smallDataMap.get(bigData.getId()); if (smallData != null) { bigData.setKey(String.valueOf(smallData.getHmpid())); bigData.setStatus(String.valueOf(smallData.getStatus())); } });
方案2:生成新列表(无副作用版)
如果不想修改原列表,可通过map生成新对象,符合Stream无副作用的函数式编程原则:
Map<Integer, SmallDataDto> smallDataMap = smallDataList.stream() .collect(Collectors.toMap(SmallDataDto::getExtraId, dto -> dto)); List<BigDataDto> resultDataList = bigDataList.stream() .map(bigData -> { // 复制原对象属性,避免修改原数据 BigDataDto updatedDto = new BigDataDto(); updatedDto.setId(bigData.getId()); updatedDto.setTimestamp(bigData.getTimestamp()); updatedDto.setValue(bigData.getValue()); SmallDataDto smallData = smallDataMap.get(bigData.getId()); if (smallData != null) { updatedDto.setKey(String.valueOf(smallData.getHmpid())); updatedDto.setStatus(String.valueOf(smallData.getStatus())); } else { // 保留原对象的空值 updatedDto.setKey(bigData.getKey()); updatedDto.setStatus(bigData.getStatus()); } return updatedDto; }) .collect(Collectors.toList());
优化说明
- 原实现时间复杂度为O(n*m),转Map后查找操作变为O(1),整体时间复杂度降至O(n+m),数据量越大效率提升越明显。
- 增加非空判断,避免原代码中
findRelated.get()可能抛出的NoSuchElementException。 - 方案2通过生成新对象实现无副作用操作,更适合需要保留原数据的场景。
内容的提问来源于stack exchange,提问作者Romillion
相关产品推荐
相关产品推荐

