Java11如何按自定义条件过滤复杂对象列表,实现按字段规则去重
Java 自定义规则分组去重实现方案
你原有思路方向正确,问题出在Comparator的实现不符合JDK规范:Comparator的compare(o1, o2)方法要求返回int值,正数代表o1排序优先级高于o2,负数代表o1排序优先级低于o2,0代表二者优先级相等,你之前直接返回对象属于语法错误,且优先级判断逻辑不完整。
方案1(易扩展写法,推荐)
通过优先级映射表定义device的优先级,后续新增设备类型时只需修改映射表即可:
// 定义设备优先级,数值越大优先级越高 Map<String, Integer> devicePriority = Map.of( "Phone", 2, "Laptop", 1 ); List<Employee> reducedEmpList = empList.stream() .collect(Collectors.groupingBy( Employee::getEmployeeId, // 每组取优先级最高的记录 Collectors.maxBy(Comparator.comparingInt(emp -> devicePriority.getOrDefault(emp.getDevice().trim().toUpperCase(), 0) )) )) .values() .stream() // 业务场景下按employeeId分组至少存在一条记录,直接拆解Optional即可 .map(Optional::get) .collect(Collectors.toList());
方案2(无额外依赖写法)
无需单独定义优先级映射表,直接在Comparator中实现优先级判断:
List<Employee> reducedEmpList = empList.stream() .collect(Collectors.groupingBy( Employee::getEmployeeId, Collectors.maxBy((e1, e2) -> { int p1 = "Phone".equalsIgnoreCase(e1.getDevice()) ? 2 : "Laptop".equalsIgnoreCase(e1.getDevice()) ? 1 : 0; int p2 = "Phone".equalsIgnoreCase(e2.getDevice()) ? 2 : "Laptop".equalsIgnoreCase(e2.getDevice()) ? 1 : 0; return Integer.compare(p1, p2); }) )) .values() .stream() .map(Optional::get) .collect(Collectors.toList());
逻辑说明
- 首先通过
Collectors.groupingBy按employeeId将同一员工的所有记录聚合到同一组 - 对每组内的记录,根据device计算优先级,Phone优先级高于Laptop,用
Collectors.maxBy筛选出每组优先级最高的记录 - 最后提取分组结果的value,拆解Optional包装后收集为最终的去重列表
扩展提示
如果同一员工存在多条同优先级的记录(例如两条Phone记录),可在Comparator中追加额外的比较规则(比如按记录更新时间倒序),即可实现更复杂的筛选逻辑。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

