优化arraylist插入性能的核心是减少扩容:预估数量时用带参构造函数;有上限时调ensurecapacity;批量插入优先用addall;必要时trimtosize释放内存。

频繁向 ArrayList 插入大量元素时,性能瓶颈几乎都来自底层数组的反复扩容 —— 每次扩容都要创建新数组、复制全部旧元素,开销叠加后非常明显。优化核心就一条:让扩容尽量少发生,最好只发生一次,甚至零次。
预估数量,初始化时指定容量
如果插入总数基本可预知(比如读取固定大小的文件、分页接口返回总条数已知),直接用带参构造函数最简洁高效:
- new ArrayList(expectedSize) 会一次性分配足够空间,后续 add 全是纯写入,无复制、无 realloc
- 比先 new ArrayList() 再调 ensureCapacity() 少一次方法调用,语义更清晰
- 例如:预计插入 8 万条日志,写 new ArrayList(80000)
不确定总数但有上限,提前调 ensureCapacity
当数据来源是流式读取、分页加载或外部 API 分批返回,但你能估算一个合理上限(比如“最多不会超 15 万”),就在循环前调一次 ensureCapacity:
- 它只在当前容量不足时才真正扩容,重复调用无副作用,也无收益
- 别设过大值(如预估 2 万却传 200 万),浪费堆内存,还可能抬高 GC 压力
- 示例:list.ensureCapacity(150000) → 后续所有 add 都跳过 grow 判断
优先用 addAll 而非循环 add
如果待插入数据已经在一个 Collection(如数组、另一个 List)里,直接用 addAll:
- addAll 内部会先计算总需容量(size + numNew),再一次性 ensureCapacityInternal,天然做了批量优化
- 避免手写 for 循环时漏掉预扩容,也省去显式调用 ensureCapacity 的步骤
- 尤其适合从数据库查询结果、JSON 解析后的 List 批量导入场景
插入完成后可选 trimToSize
如果插入后列表不再增删,且你对内存敏感(比如长期驻留缓存),可以调用 trimToSize():
- 它把底层数组大小收紧到当前 size,释放多余空间
- 注意:这是以时间换空间,会触发一次数组复制,仅在确实需要时使用
- 不建议在高频写入流程中每轮都调,得不偿失
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











