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

如何通过Stream API按ID分组并合并Test对象

按ID分组并合并Test对象的Stream API实现

定义与实例化

我定义了如下Test类(补充必要的构造方法、getter/setter以支持Stream操作):

public class Test {
    private Integer id;
    private String first;
    private String second;

    public Test(Integer id, String first, String second) {
        this.id = id;
        this.first = first;
        this.second = second;
    }

    // Getter和Setter方法
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getFirst() { return first; }
    public void setFirst(String first) { this.first = first; }
    public String getSecond() { return second; }
    public void setSecond(String second) { this.second = second; }
}

并实例化了多个对象:

Test test1 = new Test(1, "qweqwe", null);
Test test2 = new Test(2, "qweqwe", null);
Test test3 = new Test(3, "qweqwe", null);
Test test4 = new Test(1, null, "dfdsfg");
Test test5 = new Test(2, null, "dfdsfg");
Test test6 = new Test(3, null, "dfdsfg");

需求

通过Stream API按id对这些对象分组并合并,最终得到每个id对应一个完整字段的List<Test>,结果如下:

  • (1, "qweqwe", "dfdsfg")
  • (2, "qweqwe", "dfdsfg")
  • (3, "qweqwe", "dfdsfg")

当前仅能通过collect(Collectors.groupingBy(Test::getId, Collectors.toList()))得到Map<Integer, List<Test>>,不符合需求。


实现方法

方法一:分组后直接合并(groupingBy + reducing)

利用Collectors.reducing在分组时直接完成对象合并,再提取结果转为List:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

List<Test> mergedList = Arrays.asList(test1, test2, test3, test4, test5, test6)
        .stream()
        .collect(Collectors.groupingBy(
                Test::getId,
                Collectors.reducing(
                        new Test(null, null, null), // 初始化空对象
                        (testA, testB) -> {
                            // 合并逻辑:优先保留非null的字段值
                            Test merged = new Test(testA.getId(), null, null);
                            merged.setFirst(testA.getFirst() != null ? testA.getFirst() : testB.getFirst());
                            merged.setSecond(testA.getSecond() != null ? testA.getSecond() : testB.getSecond());
                            return merged;
                        }
                )
        ))
        .values() // 获取所有合并后的Test对象
        .stream()
        .collect(Collectors.toList());

方法二:先分组再遍历合并

先按id分组得到Map,再遍历每个分组的对象列表,提取非null字段合并为新对象:

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

List<Test> mergedList = Arrays.asList(test1, test2, test3, test4, test5, test6)
        .stream()
        .collect(Collectors.groupingBy(Test::getId))
        .entrySet()
        .stream()
        .map(entry -> {
            Integer id = entry.getKey();
            List<Test> testGroup = entry.getValue();
            // 提取分组内非null的first字段
            String first = testGroup.stream()
                    .map(Test::getFirst)
                    .filter(Objects::nonNull)
                    .findFirst()
                    .orElse(null);
            // 提取分组内非null的second字段
            String second = testGroup.stream()
                    .map(Test::getSecond)
                    .filter(Objects::nonNull)
                    .findFirst()
                    .orElse(null);
            return new Test(id, first, second);
        })
        .collect(Collectors.toList());

说明

两种方法的核心逻辑一致:先按id分组,再对每组内的Test对象进行字段合并,优先保留非null的字段值。需确保Test类具备对应的构造方法、getter和setter,否则无法正常操作字段。

内容的提问来源于stack exchange,提问作者hvrhand

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:35:23