Java List 去重有多种实现方式,选择取决于 是否需保留原顺序、去重依据(完整对象 vs 指定字段)及 Java 版本。以下是生产环境最常用、最安全的方案:
🎯 一句话推荐
| 场景 | 推荐方案 | 是否保序 | 时间复杂度 |
|---|---|---|---|
按 equals() 去重 | stream().distinct() | ✅ 是 | O(n) |
| 按指定字段去重 | filter + Set.add() 技巧 | ✅ 是 | O(n) |
| 极致性能(不保序) | new HashSet<>(list) | ❌ 否 | O(n) |
📦 1. 按对象整体去重(保留原顺序)
依赖 equals() 和 hashCode(),适合已正确重写这两个方法的对象。
List<String> deduped = list.stream()
.distinct() // 基于 equals() 判断,自动保序
.collect(Collectors.toList());
// 或更高效的底层写法(少一次 Stream 开销)
List<String> deduped = new ArrayList<>(new LinkedHashSet<>(list));
🔑 2. 按指定字段去重(实战高频)
需求:根据 User.getId() 或 User.getName() 去重,且保留第一次出现的元素。
// ✅ 推荐:利用 Set.add() 返回值特性,简洁高效
Set<Integer> seenIds = new HashSet<>();
List<User> deduped = list.stream()
.filter(user -> seenIds.add(user.getId())) // add 返回 false 表示已存在
.collect(Collectors.toList());
// ⚠️ 注意:若字段可能为 null,改用 Objects.hash() 或判空逻辑
Set<Object> seen = new HashSet<>();
List<User> deduped = list.stream()
.filter(u -> seen.add(u.getName() == null ? "NULL_KEY" : u.getName()))
.collect(Collectors.toList());
⚡ 3. 不关心顺序(追求极致性能)
放弃顺序可换用 HashSet,内存和速度最优。
List<User> deduped = new ArrayList<>(new HashSet<>(list));
⚠️ 核心避坑指南
- 必须重写
equals()&hashCode()
自定义对象若未重写,distinct()或Set会按内存地址比较,导致去重失败。@Data // Lombok 自动生成 public class User { private Integer id; private String name; } - 不要用
list.contains()循环去重
contains()底层是线性查找,嵌套循环会导致O(n²)性能雪崩。// ❌ 生产环境禁止 for (int i = 0; i < list.size(); i++) { for (int j = i + 1; j < list.size(); j++) { ... } } - 原列表不可变时,去重会抛异常
Arrays.asList()、List.of()返回的是只读列表,需先转ArrayList:List<String> mutable = new ArrayList<>(Arrays.asList("A", "B", "A")); List<String> deduped = new ArrayList<>(new LinkedHashSet<>(mutable));
📊 性能与适用场景对比
| 方案 | 保序 | 依赖 | 性能 | 适用场景 |
|---|---|---|---|---|
stream().distinct() | ✅ | equals/hashCode | ⭐⭐⭐ | 通用、代码简洁 |
LinkedHashSet | ✅ | equals/hashCode | ⭐⭐⭐⭐ | 大数据量、追求效率 |
filter + Set.add() | ✅ | 指定字段 | ⭐⭐⭐⭐ | 按业务字段去重 |
HashSet | ❌ | equals/hashCode | ⭐⭐⭐⭐⭐ | 顺序无关的缓存/集合处理 |
💡 调试技巧:去重前打印
list.stream().map(User::getId).distinct().count()可快速验证去重数量是否符合预期。

2599

被折叠的 条评论
为什么被折叠?



