You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 15:04:54