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

如何用Java 8 Stream从对象列表生成含匹配/不匹配项的Map<List<Emp>>

用Java 8 Stream实现Emp列表的配对与分组

首先补充Emp类的完整定义(包含必要的字段、getter/setter和toString方法):

class Emp {
    private String id;
    private String name;
    private String joinDate;
    private String terminationDate;

    // getter方法
    public String getId() { return id; }
    public String getName() { return name; }
    public String getJoinDate() { return joinDate; }
    public String getTerminationDate() { return terminationDate; }

    // setter方法
    public void setId(String id) { this.id = id; }
    public void setName(String name) { this.name = name; }
    public void setJoinDate(String joinDate) { this.joinDate = joinDate; }
    public void setTerminationDate(String terminationDate) { this.terminationDate = terminationDate; }

    // 重写toString方便查看对象内容
    @Override
    public String toString() {
        return "Emp{id='" + id + "', name='" + name + "', joinDate='" + joinDate + "', terminationDate='" + terminationDate + "'}";
    }
}

核心实现代码

以下是通过Java 8 Stream完成需求的完整代码,包含逻辑注释:

import java.util.*;
import java.util.stream.Collectors;

public class Test {
    public static void main(String[] args) {
        Emp a = new Emp();
        a.setId("1");
        a.setName("hi");
        a.setJoinDate("20220201");

        Emp b = new Emp();
        b.setId("2");
        b.setName("hi");
        b.setTerminationDate("20220201");

        Emp c = new Emp();
        c.setId("3");
        c.setName("hello");
        c.setJoinDate("20220201");

        // 新增测试用例:无匹配的Emp
        Emp d = new Emp();
        d.setId("4");
        d.setName("hello");
        d.setTerminationDate("20220301");

        List<Emp> empList = Arrays.asList(a, b, c, d);

        // 定义结果Map的键名
        final String MATCHED_PAIRS = "MATCHED_PAIRS";
        final String UNMATCHED_SINGLES = "UNMATCHED_SINGLES";

        // 核心处理逻辑
        Map<String, List<Object>> resultMap = empList.stream()
                // 第一步:按name分组,仅在同名Emp中寻找匹配
                .collect(Collectors.groupingBy(Emp::getName))
                .values()
                .stream()
                // 第二步:处理每个name分组,拆分配对与单个Emp
                .flatMap(group -> {
                    Set<Emp> matchedMark = new HashSet<>();
                    List<List<Emp>> pairs = new ArrayList<>();
                    List<Emp> singles = new ArrayList<>();

                    // 遍历分组内的Emp,寻找符合条件的配对
                    for (int i = 0; i < group.size(); i++) {
                        Emp emp1 = group.get(i);
                        if (matchedMark.contains(emp1)) continue;

                        boolean hasMatch = false;
                        for (int j = i + 1; j < group.size(); j++) {
                            Emp emp2 = group.get(j);
                            if (matchedMark.contains(emp2)) continue;

                            // 判断匹配条件:一方的joinDate等于另一方的terminationDate
                            boolean matchCondition = Objects.equals(emp1.getJoinDate(), emp2.getTerminationDate())
                                    || Objects.equals(emp2.getJoinDate(), emp1.getTerminationDate());
                            if (matchCondition) {
                                pairs.add(Arrays.asList(emp1, emp2));
                                matchedMark.add(emp1);
                                matchedMark.add(emp2);
                                hasMatch = true;
                                break;
                            }
                        }

                        if (!hasMatch) {
                            singles.add(emp1);
                        }
                    }

                    // 将配对和单个Emp合并为统一流,方便后续收集
                    List<Object> temp = new ArrayList<>();
                    temp.addAll(pairs);
                    temp.addAll(singles);
                    return temp.stream();
                })
                // 第三步:按元素类型(List=配对,Emp=单个)分组
                .collect(Collectors.partitioningBy(
                        item -> item instanceof List,
                        Collectors.toList()
                ))
                // 第四步:转换为需求指定的键名
                .entrySet()
                .stream()
                .collect(Collectors.toMap(
                        entry -> entry.getKey() ? MATCHED_PAIRS : UNMATCHED_SINGLES,
                        Map.Entry::getValue
                ));

        // 打印结果
        System.out.println("匹配的成对Emp:");
        resultMap.get(MATCHED_PAIRS).forEach(System.out::println);
        System.out.println("\n未匹配的单个Emp:");
        resultMap.get(UNMATCHED_SINGLES).forEach(System.out::println);
    }
}

逻辑说明

  1. 按名称分组:使用groupingBy将Emp列表按name字段分组,确保仅在同名Emp中筛选配对。
  2. 配对筛选:在每个名称分组内,通过双重循环检查Emp是否满足日期匹配条件,用HashSet标记已配对的Emp,避免重复处理。
  3. 结果收集:通过partitioningBy将配对的List和单个Emp分开,最后转换为指定键名的Map。

运行输出

匹配的成对Emp:
[Emp{id='1', name='hi', joinDate='20220201', terminationDate='null'}, Emp{id='2', name='hi', joinDate='null', terminationDate='20220201'}]

未匹配的单个Emp:
Emp{id='3', name='hello', joinDate='20220201', terminationDate='null'}
Emp{id='4', name='hello', joinDate='null', terminationDate='20220301'}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:20:53