优先使用removeIf()(JDK 8+),安全高效且只遍历一次;其次可倒序for循环删除;或收集索引后逆序删除;应避免正向循环中remove导致O(n²)、跳删及并发修改异常。

ArrayList 批量删除元素时,直接在遍历中调用 remove() 会引发 ConcurrentModificationException 或漏删、索引越界等问题;高效的关键是避免边遍历边修改,同时减少数组移动次数。
优先使用 removeIf()(推荐,JDK 8+)
这是最简洁、安全且高效的批量删除方式,内部采用“标记-移动”策略,只遍历一次,且自动处理索引偏移:
- 底层先遍历标记所有匹配元素,再统一把后续有效元素前移,时间复杂度接近 O(n)
- 无需手动管理索引或迭代器,代码可读性强
- 支持 Lambda 表达式,逻辑清晰
示例:
list.removeIf(x -> x % 2 == 0); // 删除所有偶数
倒序遍历 + 普通 for 循环(兼容老版本 JDK)
从后往前删,可避免因前面元素删除导致后续元素索引前移而跳过检查:
立即学习“Java免费学习笔记(深入)”;
- 每次
remove(int index)仍会触发数组复制,但不会漏删 - 适合已知删除条件较简单、且无法升级 JDK 的场景
示例:
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i) == null || list.get(i).length() == 0) {
list.remove(i);
}
}收集待删索引再批量移除(需额外空间,但可控性强)
先遍历记录所有要删的索引(或引用),再逆序删除或用 removeAll():
- 若删除条件复杂(如依赖多个字段或外部状态),这种方式逻辑更清晰
- 用
LinkedHashSet或ArrayList<integer></integer>存索引,注意逆序删除防止索引错位 - 也可转为临时集合后调用
removeAll(tempSet),但需确保元素equals/hashCode正确
避免低效写法
以下操作应尽量避开:
- 正向 for 循环中调用
remove(Object):每删一个,后面所有元素前移,整体退化为 O(n²) - 用普通 for 遍历时调用
remove(int)却不调整循环变量i:导致跳过下一个元素 - 用增强 for(for-each)或 Iterator 直接调用
remove()以外的方法修改集合:抛出并发修改异常
不复杂但容易忽略。


















