1. 概述
在本篇文章中,我们将介绍几种在 Java 8 Stream 中对集合中的元素执行操作,并在操作完成后将其从原集合中移除的方法。
虽然 Stream API 主要用于处理不可变的数据流,但有时我们仍需要在操作后将某些元素从原始集合中清除。这篇文章将围绕这一场景,提供几种实用且高效的实现方式。
2. 准备工作
首先我们定义一个简单的 Item
类,它只有一个 int
类型的字段,并包含两个方法:
isQualified()
:判断该对象是否满足操作条件operate()
:执行具体操作逻辑
class Item {
private int value;
// constructors
public boolean isQualified() {
return value % 2 == 0;
}
public void operate() {
System.out.println("Even Number");
}
}
然后我们初始化一个包含多个 Item
的列表作为数据源:
List<Item> itemList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
itemList.add(new Item(i));
}
3. 元素过滤
✅ 在很多场景下,如果只是想对部分元素进行操作而不需要从原集合中移除它们,使用 Stream#filter
就足够了:
itemList.stream()
.filter(item -> item.isQualified())
...
这种方式简单粗暴,适用于大多数只读操作。
4. 执行操作并移除元素
4.1. 使用 Collection.removeIf
这是最推荐的方式之一,直接利用 Stream 进行操作后再调用 removeIf
移除符合条件的元素。
我们可以先创建一个 Predicate 来判断哪些元素是“合格”的:
Predicate<Item> isQualified = item -> item.isQualified();
接着对这些元素执行操作:
itemList.stream()
.filter(isQualified)
.forEach(item -> item.operate());
操作完成后,使用相同的 Predicate 调用 removeIf
方法即可从原集合中移除这些元素:
itemList.removeIf(isQualified);
⚠️ 注意:removeIf
内部使用的是 Iterator
实现,因此它是线程安全的(在单线程环境下),并且能避免并发修改异常。
4.2. 使用 Collection.removeAll
如果你不想用 Predicate,也可以先将已处理过的元素收集到另一个列表中,最后通过 removeAll
一次性移除:
List<Item> operatedList = new ArrayList<>();
itemList.stream()
.filter(item -> item.isQualified())
.forEach(item -> {
item.operate();
operatedList.add(item);
});
itemList.removeAll(operatedList);
⚠️ 注意:removeAll
底层使用的是普通的 for 循环匹配元素,效率略低于 removeIf
,尤其在大数据量时要谨慎使用。
5. 总结
本文介绍了如何在 Java 8 Stream 中对集合元素执行操作并将其从原集合中移除的几种常见方式:
- ✅ 最推荐:使用
removeIf
结合 Predicate - ⚠️ 备选方案:使用
removeAll
配合额外的 List 存储已操作元素
两种方式各有优劣,前者更高效简洁,后者语义清晰但性能稍差。
完整代码和测试用例可以在 GitHub 仓库 中找到。