ArrayList性能优化需关注扩容、非尾部增删和遍历安全三方面:预设合理初始容量避免频繁扩容;仅在末尾增删以保持O(1)效率;遍历时用Iterator.remove或倒序循环防止漏删;多线程场景须选用线程安全替代方案。

ArrayList 看似简单,但用错场景或忽略底层机制,很容易拖慢应用。核心问题集中在扩容、操作位置和遍历方式三方面,避开这几个坑,性能提升立竿见影。
预设合理初始容量,避免频繁扩容
默认构造的 ArrayList 初始容量为 0,首次 add 才分配 10 个空间;后续每次扩容都是旧容量的 1.5 倍,并触发整块数组复制。百万级数据下可能扩容 30 次以上,每次复制都消耗 CPU 和内存。
- 明确知道数据量:直接传入预估大小,例如 new ArrayList<>(100000)
- 无法精确预估:给一个偏大的保守值(如预期的 1.2 倍),也能大幅减少扩容次数
- 注意:不是越大越好,过度预留会浪费堆内存,尤其在对象生命周期短、数量多的场景
避免在非尾部位置增删元素
ArrayList 底层是数组,插入或删除索引 i 处的元素,需要把 i 后所有元素整体前移或后移。头部操作代价最高,时间复杂度 O(n)。
- 只在末尾 add 或 remove:这是最高效的操作,接近 O(1)
- 需要频繁中间/头部增删:改用 LinkedList(适合增删多、查询少)或考虑其他结构(如 ArrayDeque 用于栈/队列场景)
- 若必须用 ArrayList 做批量删除:优先用 stream.filter 生成新列表,而不是逐个 remove
遍历时别边遍历边用 list.remove(i)
普通 for 循环中调用 remove(i),会导致后续元素索引前移,而循环变量 i 仍递增,结果跳过下一个元素——漏删是常态。
- 安全做法一:用 Iterator 遍历,调用 iterator.remove()(它会自动同步内部游标)
- 安全做法二:倒序 for 循环(i 从 size-1 递减),删除不影响前面未访问的索引
- 更推荐:用 stream 过滤,语义清晰且无并发风险,例如 list.stream().filter(x -> !x.equals("a")).collect(Collectors.toList())
多线程环境下不能直接共享 ArrayList
add、remove、甚至遍历过程都不是原子操作。两个线程同时写,可能覆盖数据、size 错误;一个线程遍历、另一个写,会抛 ConcurrentModificationException。
- 读多写少且允许弱一致性:用 CopyOnWriteArrayList(适合监听器列表等场景)
- 需要强一致性且写不频繁:用 Collections.synchronizedList(new ArrayList<>()),但注意迭代时需手动同步
- 高并发写+读:考虑并发容器如 ConcurrentHashMap 配合其他结构,或分段加锁设计



















