如何在HashSet中基于属性对不可修改的Employee实例去重
解决无法自定义equals/hashCode时的Employee去重问题
能不能按name剔除重复的Employee?
当然可以,但不能直接用默认的HashSet——因为它完全依赖目标类的equals()和hashCode()方法判断唯一性。给你几个可行的落地方案:
方案1:用TreeSet指定自定义比较器
TreeSet不依赖equals()和hashCode(),而是通过Comparator的返回值判断元素是否重复。只要两个Employee的name相同,比较器返回0,TreeSet就会判定为重复元素,不会添加:
Set<Employee> uniqueEmpSet = new TreeSet<>(Comparator.comparing(Employee::getName)); uniqueEmpSet.add(emp); uniqueEmpSet.add(emp2); // 此时集合中只会保留一个name相同的实例
注意:TreeSet会自动按name排序,如果不需要有序性也没关系,它依然能完成去重逻辑。
方案2:用HashMap以name为键去重
把name作为HashMap的key,Employee作为value,重复的name会自动覆盖旧值,最后取values集合就是去重后的结果:
Map<String, Employee> empMap = new HashMap<>(); // 可以自主控制保留哪个实例:比如优先保留先添加的,或者后添加的 empMap.put(emp.getName(), emp); empMap.put(emp2.getName(), emp2); // 后添加的会覆盖同name的旧实例 // 转成Set或者直接使用values集合 Set<Employee> uniqueEmpSet = new HashSet<>(empMap.values());
这个方案灵活性最高,能明确控制当name重复时保留哪一个实例。
方案3:自定义包装类(如果允许新增类)
给Employee套一层包装类,在包装类里重写equals()和hashCode(),完全基于name判断:
class EmployeeWrapper { private final Employee emp; public EmployeeWrapper(Employee emp) { this.emp = emp; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; EmployeeWrapper that = (EmployeeWrapper) o; return Objects.equals(emp.getName(), that.emp.getName()); } @Override public int hashCode() { return Objects.hash(emp.getName()); } public Employee getEmployee() { return emp; } }
使用时把Employee包装后存入HashSet,最后可以通过getEmployee()提取原始实例。
改用ArrayList合适吗?
ArrayList本身没有自动去重能力,要实现去重必须手动检查:
List<Employee> empList = new ArrayList<>(); empList.add(emp); // 添加新实例前遍历检查name是否重复 boolean isDuplicate = empList.stream().anyMatch(e -> e.getName().equals(emp2.getName())); if (!isDuplicate) { empList.add(emp2); }
这种方法的核心问题是性能差,每次添加都要遍历整个列表,数据量大时时间复杂度是O(n),远不如前面基于哈希或树的集合高效。除非你的数据量极小,否则不推荐用ArrayList做去重。
内容的提问来源于stack exchange,提问作者bon mohanty
相关产品推荐
相关产品推荐

