ArrayList中间删除最耗性能,因其需将索引后所有元素前移,移动量达size−index−1;越靠前删除,移动元素越多,如删索引500处元素需移动近99500个引用。

删除中间位置的元素,是 ArrayList 中开销最大的 remove 场景之一——不是因为“删了一个”,而是因为它迫使大量后续元素整体前移。
为什么中间删除最耗性能
ArrayList 底层是数组,不支持“挖空”某个位置。调用 remove(int index) 时,它实际执行的是:
- 把 index + 1 到末尾 的所有元素,统一向前拷贝一位;
- 这个拷贝由 JVM 高度优化的 System.arraycopy 完成,但仍是内存块级移动,不可省略;
- 移动数量为 size − index − 1,越靠近开头,移动量越大。
例如:一个含 10 万元素的列表,删除索引 500 处的元素,就要移动约 99,500 个引用——几乎整个数组。
remove(Object o) 的双重开销更隐蔽
相比直接按索引删,按值删除(remove(Object o))会先触发一次线性扫描:
- 从下标 0 开始逐个调用 equals() 匹配,平均要查一半才能找到;
- 找到后,再执行和 remove(int index) 完全相同的前移操作;
- 若目标在开头,查找快、移动慢;若在末尾,查找慢、移动几乎为零——但总耗时仍显著高于直接索引删除。
遍历时误用 remove 的连锁崩溃
在 for 循环中边遍历边调 remove(Object o),会引发两重恶化:
- 每次删除都导致后续元素下标全部减 1,造成下一轮循环跳过下一个元素(漏删);
- 外层循环每走一步,内层 remove 都重新从头扫描,时间复杂度退化为 O(n²);
- 迭代器检测到 modCount 变更,直接抛 ConcurrentModificationException。
真正能降开销的实用办法
ArrayList 没有“批量区间删除”能力,但可以规避重复移动:
- 需删多个时,先用 LinkedHashSet 或 ArrayList 收集所有待删索引(保持顺序或去重);
- 然后倒序遍历索引列表,逐个调 remove(int index);
- 倒序可确保前面的删除不影响后面索引的有效性,避免移动错位,也减少总移动量。
这种模式虽不能合并 arraycopy,但让多次删除的总移动次数趋近理论最小值。

















