如何用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); } }
逻辑说明
- 按名称分组:使用
groupingBy将Emp列表按name字段分组,确保仅在同名Emp中筛选配对。 - 配对筛选:在每个名称分组内,通过双重循环检查Emp是否满足日期匹配条件,用
HashSet标记已配对的Emp,避免重复处理。 - 结果收集:通过
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
相关产品推荐
相关产品推荐

