最常用、最稳妥的ArrayList去重方式是借助LinkedHashSet,它既能自动剔除重复元素,又能保留原始插入顺序;Java 8+还可使用Stream.distinct(),语义清晰但性能略低;自定义对象需重写equals和hashCode。

ArrayList 去重最常用、最稳妥的方式是借助 LinkedHashSet,它既能自动剔除重复元素,又能保留原始插入顺序。如果你用的是 Java 8+,Stream.distinct() 也是简洁高效的选择。关键要看你是否需要维持顺序、是否处理自定义对象,以及对性能或代码可读性的侧重。
保持顺序的去重:用 LinkedHashSet
这是开发中最推荐的基础方案,尤其适合字符串、数字等基本类型或已正确重写 equals 和 hashCode 的对象。
- 原理:LinkedHashSet 底层基于哈希表 + 双向链表,去重同时记录添加顺序
- 一行核心代码:
new ArrayList(new LinkedHashSet(originalList)) - 注意:原 list 不会被修改,需用返回的新 list 替换
Java 8+ 推荐:Stream.distinct()
函数式风格,语义清晰,适合链式调用场景(比如过滤后再去重)。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 写法:
list.stream().distinct().collect(Collectors.toList()) - 底层仍依赖
equals判断相等性,对自定义对象同样要求重写equals和hashCode - 性能略低于 LinkedHashSet(因涉及流创建和中间操作),但差异在万级数据内几乎不可感知
自定义对象去重的关键前提
如果 ArrayList 存的是你自己写的类(如 Product、User),直接套用上面方法会失效——因为默认 equals 比较的是引用地址。
- 必须重写类的
equals()方法,明确以哪些字段判定“重复”(例如只看id或name) - 必须同步重写
hashCode(),否则在 HashSet/LinkedHashSet 中可能无法正常识别重复 - 不重写就去重,结果很可能仍是满屏重复
其他可用但慎用的方法
这些方式存在明显短板,仅建议在特殊限制下临时使用:
-
双重 for 循环 + remove():边遍历边删,容易因索引错位漏删或抛
ConcurrentModificationException;效率低(O(n²)),大数据量卡顿明显 - 单独用 HashSet:去重快,但完全打乱原有顺序,除非业务真不在乎顺序,否则不推荐
-
手动遍历 + contains() 新建 list:逻辑直白,但每次
contains()都是 O(n) 查找,整体接近 O(n²),小数据凑合,大一点就慢

















