1. 概述
本文将系统介绍在 Java 中从 ArrayList
删除元素的多种方式。我们先准备一个基础方法,用于生成一个包含运动项目的列表:
List<String> getSportList() {
List<String> sports = new ArrayList<>();
sports.add("Football");
sports.add("Basketball");
sports.add("Baseball");
sports.add("Boxing");
sports.add("Cycling");
return sports;
}
接下来,我们将基于这个列表,演示各种删除元素的技巧。
2. 使用 ArrayList#remove 方法
ArrayList
提供了两个重载的 remove
方法:
✅ remove(int index)
—— 根据索引删除
✅ remove(Object o)
—— 根据元素值删除(仅删除第一次出现的位置)
下面我们逐一说明。
2.1 按索引删除
调用 remove(index)
会删除指定位置的元素,并将后续元素左移,同时返回被删除的元素。这是最直接也最高效的方式之一。
示例:
List<String> sports = getSportList();
assertThat(sports).hasSize(5).contains("Basketball");
sports.remove(1); // 删除索引为1的元素 "Basketball"
assertThat(sports).hasSize(4).doesNotContain("Basketball");
⚠️ 注意:索引从 0 开始,删除后列表会自动调整大小。
2.2 按元素值删除
通过传入具体对象调用 remove(Object)
,会删除该元素第一次出现的位置。如果没有匹配项,列表不变。
List<String> sports = getSportList();
assertThat(sports).hasSize(5).contains("Basketball");
sports.remove("Basketball");
assertThat(sports).hasSize(4).doesNotContain("Basketball");
✅ 这种方式适合你知道要删谁,但不知道它在哪的情况。
❌ 但注意:只删第一个匹配项,重复元素需特殊处理。
2.3 删除最后一个元素
日常开发中,“删末尾”是个高频操作。传统做法是结合 size()
和 remove(index)
:
List<String> sports = getSportList();
List<String> expected = List.of("Football", "Basketball", "Baseball", "Boxing");
sports.remove(sports.size() - 1); // 删除最后一个
assertThat(sports).isEqualTo(expected);
但从 JDK 21 起,List
接口新增了一个更语义化的 API:removeLast()
。
List<String> sports = getSportList();
List<String> expected = List.of("Football", "Basketball", "Baseball", "Boxing");
sports.removeLast();
assertThat(sports).isEqualTo(expected);
✅ 推荐:如果你的项目已升级到 JDK 21+,removeLast()
更简洁、可读性更强,是首选方式。
⚠️ 注意:调用前需确保列表非空,否则抛 NoSuchElementException
。
3. 遍历过程中删除元素
这是个经典“踩坑”场景:直接在 for-each
循环中调用 list.remove()
会触发 ConcurrentModificationException
。
正确做法是使用 Iterator,并调用其 remove()
方法:
List<String> sports = getSportList();
assertThat(sports).hasSize(5).contains("Basketball");
Iterator<String> iterator = sports.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("Basketball")) {
iterator.remove(); // 安全删除
break;
}
}
assertThat(sports).hasSize(4).doesNotContain("Basketball");
✅ 关键点:
- 必须使用
Iterator.remove()
,而不是List.remove()
iterator.remove()
是唯一允许在遍历时安全删除的方式- 调用前必须先调用
next()
4. 使用 ArrayList#removeIf(JDK 8+)
从 JDK 8 开始,Collection
接口引入了 removeIf(Predicate)
方法,支持基于条件批量删除,代码更函数式、更简洁。
List<String> sports = getSportList();
assertThat(sports).hasSize(5).contains("Basketball");
sports.removeIf(p -> p.equals("Basketball"));
assertThat(sports).hasSize(4).doesNotContain("Basketball");
✅ 优势:
- 一行代码搞定条件删除
- 内部自动处理迭代器,无需手动写循环
- 支持复杂条件,比如
s -> s.startsWith("B")
📌 示例:删除所有以 "B" 开头的运动
sports.removeIf(s -> s.startsWith("B"));
// 结果:["Football", "Cycling"]
⚠️ 注意:removeIf
是立即执行的,会直接修改原列表。
5. 总结
方法 | 适用场景 | JDK 版本 | 是否推荐 |
---|---|---|---|
remove(index) |
已知索引 | 所有版本 | ✅ |
remove(object) |
删除首个匹配元素 | 所有版本 | ✅ |
removeLast() |
删除末尾元素 | JDK 21+ | ✅ 推荐新项目使用 |
Iterator.remove() |
遍历中按条件删除 | 所有版本 | ✅ 必须用它 |
removeIf(predicate) |
条件批量删除 | JDK 8+ | ✅ 强烈推荐 |
📌 最佳实践建议:
- 能用
removeIf
就不用手动遍历 - JDK 21+ 优先使用
removeLast()
- 遍历时删除必须用
Iterator
- 注意空指针和越界问题
所有示例代码已托管至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-collections-array-list