使用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
相关产品推荐
相关产品推荐

