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

Java 8中如何基于指定属性从列表移除另一列表的重复元素?

问题描述

我定义了如下Employee类:

public class Employee {
   private String empId;
   private String name;
   private String group;
   private String salary;       
}

现有两个Employee类型的列表:

List<Employee> listEmployeesA = new ArrayList<>(List.of(
 new Employee("101","Mark", "A", 20000),
 new Employee("102","Tom", "B", 3000),
 new Employee("103","Travis", "C", 5000),
 new Employee("104","Diana", null, 3500),
 new Employee("105","Keith", "D", 4200),
 new Employee("106","Liam", "E", 6500),
 new Employee("107","Whitney", "F", 6100),
 new Employee("108","Tina", null,2900),
 new Employee("109","Patrick", "G", 3400)
));

List<Employee> listEmployeesB = new ArrayList<>(List.of(
 new Employee("101","Mark", "A", 20000),
 new Employee("103","Travis", "C", 5000),
 new Employee("104","Diana", null, 3500)
));

需要从listEmployeesA中移除所有在listEmployeesB中存在的元素,判断重复仅依据empId、name和group属性,不考虑salary,实现类似listEmployeesA.removeAll(listEmployeesB)的效果,最终得到如下结果:

Employee("102","Tom", "B", 3000),
Employee("105","Keith", "D", 4200),
Employee("106","Liam", "E", 6500),
Employee("107","Whitney", "F", 6100),
Employee("108","Tina", null,2900),
Employee("109","Patrick", "G", 3400)
解决方案

方法一:重写Employee的equals()和hashCode()方法

List.removeAll()依赖对象的equals()判断是否相等,直接重写这两个方法,只对比empId、name、group三个属性,同时处理group为null的情况:

public class Employee {
   private String empId;
   private String name;
   private String group;
   private String salary;       

   // 构造方法、getter/setter自行补充

   @Override
   public boolean equals(Object o) {
       if (this == o) return true;
       if (o == null || getClass() != o.getClass()) return false;
       Employee employee = (Employee) o;
       return Objects.equals(empId, employee.empId) &&
               Objects.equals(name, employee.name) &&
               Objects.equals(group, employee.group);
   }

   @Override
   public int hashCode() {
       return Objects.hash(empId, name, group);
   }
}

之后直接调用方法即可:

listEmployeesA.removeAll(listEmployeesB);

执行后listEmployeesA就会得到目标结果。

方法二:不修改Employee类,用Stream API过滤

如果不想改动原类,可先把listEmployeesB的元素转换成包含目标属性的唯一标识集合,再用Stream过滤listEmployeesA:

// Java 8+ 用List<Object>作为唯一标识
Set<List<Object>> bKeys = listEmployeesB.stream()
        .map(emp -> Arrays.asList(emp.getEmpId(), emp.getName(), emp.getGroup()))
        .collect(Collectors.toSet());

List<Employee> result = listEmployeesA.stream()
        .filter(emp -> !bKeys.contains(Arrays.asList(emp.getEmpId(), emp.getName(), emp.getGroup())))
        .collect(Collectors.toList());

如果是Java 16+,用record定义更清晰的标识类:

record EmployeeKey(String empId, String name, String group) {}

Set<EmployeeKey> bKeys = listEmployeesB.stream()
        .map(emp -> new EmployeeKey(emp.getEmpId(), emp.getName(), emp.getGroup()))
        .collect(Collectors.toSet());

List<Employee> result = listEmployeesA.stream()
        .filter(emp -> !bKeys.contains(new EmployeeKey(emp.getEmpId(), emp.getName(), emp.getGroup())))
        .collect(Collectors.toList());

方法三:使用removeIf()方法

直接调用集合的removeIf(),结合B列表的匹配逻辑:

listEmployeesA.removeIf(empA -> listEmployeesB.stream()
        .anyMatch(empB -> Objects.equals(empA.getEmpId(), empB.getEmpId())
                && Objects.equals(empA.getName(), empB.getName())
                && Objects.equals(empA.getGroup(), empB.getGroup())));

这种写法无需额外集合,但如果listEmployeesB数据量大,性能会较低(时间复杂度O(n*m)),适合小数据量场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:25:51