1. 引言
本文将介绍如何从List中移除重复元素的三种实现方式:
✅ 原生Java实现
✅ Guava工具库实现
✅ Java 8 Lambda表达式实现
本文属于"Java基础回顾"系列,面向有经验的开发者,基础概念将简略带过。
2. 使用原生Java移除重复元素
通过Java集合框架的Set特性可快速去重:
public void
givenListContainsDuplicates_whenRemovingDuplicatesWithPlainJava_thenCorrect() {
List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
List<Integer> listWithoutDuplicates = new ArrayList<>(
new HashSet<>(listWithDuplicates));
assertThat(listWithoutDuplicates, hasSize(5));
assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2));
}
⚠️ 关键点:
- 原始List保持不变
- 使用
HashSet
会导致元素顺序丢失(示例中顺序可能变为[0,1,2,3,5]
)
若需保留原始顺序,改用LinkedHashSet
:
public void
givenListContainsDuplicates_whenRemovingDuplicatesPreservingOrderWithPlainJava_thenCorrect() {
List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
List<Integer> listWithoutDuplicates = new ArrayList<>(
new LinkedHashSet<>(listWithDuplicates));
assertThat(listWithoutDuplicates, hasSize(5));
assertThat(listWithoutDuplicates, containsInRelativeOrder(5, 0, 3, 1, 2));
}
3. 使用Guava移除重复元素
Guava提供更简洁的API实现相同功能:
public void
givenListContainsDuplicates_whenRemovingDuplicatesWithGuava_thenCorrect() {
List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
List<Integer> listWithoutDuplicates
= Lists.newArrayList(Sets.newHashSet(listWithDuplicates));
assertThat(listWithoutDuplicates, hasSize(5));
assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2));
}
❌ 注意:
- 默认使用
HashSet
,顺序不保证 - 需保留顺序时改用
Sets.newLinkedHashSet()
:
public void
givenListContainsDuplicates_whenRemovingDuplicatesPreservingOrderWithGuava_thenCorrect() {
List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
List<Integer> listWithoutDuplicates
= Lists.newArrayList(Sets.newLinkedHashSet(listWithDuplicates));
assertThat(listWithoutDuplicates, hasSize(5));
assertThat(listWithoutDuplicates, containsInRelativeOrder(5, 0, 3, 1, 2));
}
4. 使用Java 8 Lambda移除重复元素
Java 8的Stream API提供最优雅的解决方案:
public void
givenListContainsDuplicates_whenRemovingDuplicatesWithJava8_thenCorrect() {
List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0);
List<Integer> listWithoutDuplicates = listWithDuplicates.stream()
.distinct()
.collect(Collectors.toList());
assertThat(listWithoutDuplicates, hasSize(5));
assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2));
}
✅ 核心优势:
distinct()
方法自动保留首次出现的元素顺序- 代码简洁,链式调用可读性强
- 底层基于
equals()
方法判断重复
5. 总结
三种方案对比:
实现方式 | 代码简洁度 | 顺序保留 | 性能 | 适用场景 |
---|---|---|---|---|
原生Java | ⭐⭐ | 可选 | O(n) | 无依赖环境 |
Guava | ⭐⭐⭐ | 可选 | O(n) | 已引入Guava项目 |
Java 8 Stream | ⭐⭐⭐⭐ | ✅ | O(n) | Java 8+环境 |
所有示例代码可在GitHub项目获取,Maven项目可直接导入运行。
踩坑提醒:
- 使用
HashSet
去重时,务必确认元素是否已实现hashCode()
和equals()
- 大数据量场景下,
distinct()
的内存消耗需关注(底层使用LinkedHashSet
)