去重应优先选用Set,因其天然支持去重;HashSet最快但无序,LinkedHashSet保持插入顺序,TreeSet自动排序;List需借助Stream或Set手动去重,本质仍依赖Set逻辑。

去重时优先选 Set,除非你需要保留插入顺序或允许重复元素——但那就不是“去重”了。
Set 天然去重,适合纯粹去重需求
Set 接口的实现类(如 HashSet、LinkedHashSet、TreeSet)在设计上就禁止重复元素。添加时自动判断是否已存在,重复元素直接被忽略。
-
HashSet:基于哈希表,去重快(平均 O(1)),但不保证顺序 -
LinkedHashSet:按插入顺序保存元素,去重同时维持顺序,性能略低于 HashSet -
TreeSet:自动排序(自然序或自定义比较器),去重 + 升序,但插入是 O(log n)
List 不自带去重能力,需手动处理
List 是有序可重复集合,本身不做任何去重。若用 List 去重,必须额外编码,常见方式有:
- 遍历原列表,逐个 add 到新 Set 再转回 List(简单但多一次转换)
- 用 Java 8 Stream:
list.stream().distinct().collect(Collectors.toList()) - 手写双循环或借助 Set 辅助判断(效率低,不推荐)
这些操作本质仍是依赖 Set 的去重逻辑,List 只是最终容器。
立即学习“Java免费学习笔记(深入)”;
选谁,关键看你要不要“顺序”和“排序”
如果只关心“哪些元素出现过”,用 HashSet 最轻量;
如果还要保持添加时的顺序,选 LinkedHashSet;
如果结果需要排序(比如去重后直接展示),TreeSet 更省事;
如果业务强依赖 List 接口(如已有方法签名限定为 List),再考虑用 Stream.distinct() 或包装成不可变 List。
注意 null 和自定义对象的细节
HashSet 和 LinkedHashSet 允许一个 null;TreeSet 默认不允许(会抛 NullPointerException),除非用空值安全的比较器。
自定义对象放入 Set 去重,必须正确重写 equals() 和 hashCode();TreeSet 还需实现 Comparable 或传入 Comparator。
基本上就这些。去重不是 List 的职责,硬用它只会绕弯路。










