1. 概述
在本篇文章中,我们将介绍 四种不同的方式从 Java 的 Collections 中移除满足特定条件(谓词)的元素。
同时,我们也会指出一些使用过程中需要注意的细节和潜在问题。
2. 定义集合
我们先介绍两种会直接修改原始数据结构的方法。然后再来看两种不会修改原集合、而是创建一个新集合的方式。
在示例中,我们都使用如下这个 Collection<String>
:
Collection<String> names = new ArrayList<>();
names.add("John");
names.add("Ana");
names.add("Mary");
names.add("Anthony");
names.add("Mark");
3. 使用 Iterator 删除元素
Java 的 Iterator 提供了遍历并逐个删除集合中元素的能力。
要实现这一点,首先需要调用集合的 iterator() 方法获取迭代器实例,然后通过 next() 遍历元素,并使用 remove() 删除符合条件的元素:
Iterator<String> i = names.iterator();
while(i.hasNext()) {
String e = i.next();
if (e.startsWith("A")) {
i.remove();
}
}
虽然这种方式简单直接,但也有几个需要注意的地方:
✅ 优点:
- 适用于所有实现了
Iterator
的集合类型
⚠️ 注意:
- 如果在遍历过程中直接对集合进行结构性修改(比如用
remove()
之外的方式),可能会抛出 ConcurrentModificationException - 必须先调用
next()
才能调用remove()
,否则会抛异常 - 对于不同集合类型,
remove()
的实现机制不同:ArrayList.Iterator
删除元素后会将后续元素左移LinkedList.Iterator
只需调整指针即可- 因此,在频繁删除操作下,
LinkedList
性能更优
4. Java 8 中的 Collection.removeIf()
Java 8 在 Collection
接口中新增了一个方法 —— removeIf(Predicate),它提供了一种更加简洁的方式来根据谓词删除元素:
names.removeIf(e -> e.startsWith("A"));
相比使用 Iterator
,removeIf()
在 ArrayList
和 LinkedList
上表现更为一致:
✅ 亮点:
- 内部做了优化处理
ArrayList
覆盖了默认实现,采用两轮遍历策略:- 第一轮标记匹配的元素
- 第二轮统一删除并移动其余元素
这样避免了多次移动数组元素带来的性能损耗。
5. Java 8 引入的 Stream
Java 8 带来了强大的 Stream API,以及配套的 Collectors 工具类。
大多数 Stream 操作并不会修改源集合,而是生成新的集合副本。
5.1. 使用 Stream 过滤元素
使用 Stream 来“删除”元素其实是一种过滤操作,非常简单粗暴:
Collection<String> filteredCollection = names
.stream()
.filter(e -> !e.startsWith("A"))
.collect(Collectors.toList());
这种方式不会影响原始集合,适合在不可变编程或函数式风格中使用。
⚠️ 注意内存开销:
- 创建了新的集合对象,会增加内存占用
- 不适合大数据量下的频繁操作
5.2. 使用 Collectors.partitioningBy
有时候我们不仅想得到不匹配的元素,还想保留匹配的部分。这时候就可以使用 *Collectors.partitioningBy*:
Map<Boolean, List<String>> classifiedElements = names
.stream()
.collect(Collectors.partitioningBy((String e) ->
!e.startsWith("A")));
String matching = String.join(",",
classifiedElements.get(true));
String nonMatching = String.join(",",
classifiedElements.get(false));
该方法返回一个 Map,只包含两个键:true
和 false
,分别对应满足条件和不满足条件的元素列表。
6. 小结
本文介绍了多种在 Java 集合中删除元素的方法及其适用场景:
方法 | 是否修改原集合 | 性能特点 | 适用场景 |
---|---|---|---|
Iterator.remove() | ✅ 是 | LinkedList 更快 | 精确控制流程 |
Collection.removeIf() | ✅ 是 | 统一优化处理 | 简洁表达删除逻辑 |
Stream.filter() + collect() | ❌ 否 | 新建集合 | 不可变/函数式编程 |
Collectors.partitioningBy() | ❌ 否 | 分类结果 | 同时需要两类数据 |
你可以在这里找到完整代码示例:GitHub 项目地址