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

使用HashSet提取ArrayList重复项时结果为空的问题排查

问题:从ArrayList提取重复项时结果为空的原因及解决办法

我尝试用Set从数据库填充的ArrayList里提取重复项,代码如下:

void getDuplicateHashTest() { 
    List<BroadcastItem> allDataStoreItems = itemsDAO.getAllItems(); 
    Set<BroadcastItem> setOfAllData = new HashSet<>(allDataStoreItems); 
    List<BroadcastItem> diff = new ArrayList<>(setOfAllData); 
    allDataStoreItems.removeAll(diff); 
}

原本以为最后一行代码会移除列表里的非重复项,结果打印allDataStoreItems.size()得到的是0,但Set和diff的元素数量是正确的,这到底哪里错了?


问题根源:BroadcastItem未正确重写equals()和hashCode()

HashSet判断元素是否重复的核心逻辑是:两个对象的hashCode()值相等,且通过equals()比较返回true。如果你的BroadcastItem类没有重写这两个方法,会默认使用Object类的实现——也就是基于对象的内存地址来判断是否相等。

这就会导致一个关键问题:从数据库查出来的BroadcastItem,哪怕数据内容完全一致,也是不同的对象实例(内存地址不同)。此时HashSet会把所有对象都当成唯一元素存入,setOfAllData的大小和原列表allDataStoreItems完全一样。当你调用allDataStoreItems.removeAll(diff)时,diff包含了原列表的所有元素(因为Set把所有实例都当成唯一的),所以removeAll之后原列表直接被清空,自然size为0。

解决步骤

1. 为BroadcastItem重写equals()和hashCode()

根据你定义“重复”的标准来重写这两个方法,比如如果两个BroadcastItem的id相同就算重复,代码示例如下:

import java.util.Objects;

public class BroadcastItem {
    // 假设你的类有id字段
    private String id;

    // 其他字段、构造方法、getter/setter省略

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BroadcastItem that = (BroadcastItem) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

2. 修正提取重复项的逻辑

你当前的逻辑其实有问题,就算重写了方法,removeAll(diff)得到的是原列表中不在去重列表里的元素,这并不是你想要的重复项。正确提取重复项的方式可以这样写:

void getDuplicateHashTest() { 
    List<BroadcastItem> allDataStoreItems = itemsDAO.getAllItems(); 
    Set<BroadcastItem> uniqueItems = new HashSet<>();
    Set<BroadcastItem> duplicateItems = new HashSet<>();

    // 先找出所有重复出现过的元素(每个重复元素只存一次)
    for (BroadcastItem item : allDataStoreItems) {
        if (!uniqueItems.add(item)) {
            // 添加失败说明已经存在,是重复项
            duplicateItems.add(item);
        }
    }

    // 如果需要原列表中所有重复的实例(包括多次出现的),可以再遍历一次
    List<BroadcastItem> allDuplicateInstances = new ArrayList<>();
    for (BroadcastItem item : allDataStoreItems) {
        if (duplicateItems.contains(item)) {
            allDuplicateInstances.add(item);
        }
    }

    // 现在duplicateItems是去重后的重复元素集合,allDuplicateInstances是所有重复的实例列表
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:21:41