应预估数据量并显式指定arraylist初始容量,如new arraylist(5000),或在批量添加前调用ensurecapacity;避免addall链式调用和默认容量导致的频繁扩容。

在业务开发中避免 ArrayList 频繁内存分配,核心是**让数组容量尽量“一步到位”**,减少 grow() 调用次数。因为每次扩容都要 new 数组 + System.arraycopy,开销是 O(n),尤其在批量导入、日志聚合、订单汇总等场景下,容易成为性能瓶颈。
预估数据量,显式指定初始容量
这是最直接、最有效的做法。ArrayList 默认初始容量为 10,若你明确知道要存 5000 条订单、8 万条日志或 200 个配置项,就别用 new ArrayList()。
- 推荐写法:
new ArrayList(expectedSize),比如new ArrayList(5000) - 小技巧:可略多预留 5%~10%,例如预估 950 条,设为 1000,避免刚好卡在扩容边界
- 注意:initialCapacity 传 0 是合法的(创建空数组),但传负数会抛
IllegalArgumentException
批量添加前调用 ensureCapacity
适用于无法在构造时确定容量,但运行时能提前获知规模的场景。比如从数据库查出一批记录再封装进 List,可在查询后、遍历前统一申请空间。
- 示例:
list.ensureCapacity(resultSet.size()) - 它只扩容、不改变 size,也不会触发任何 add 操作,纯粹是内存预分配
- 比循环中反复 add 更高效,也比构造时硬编码更灵活
慎用 addAll,优先考虑容量匹配
addAll() 内部会先检查容量是否足够,不够则调用 grow()。但如果传入的是另一个未预设容量的 ArrayList,它自身可能已多次扩容,此时再 addAll 进来,容易引发“二次扩容”。
- 建议:接收方 List 显式初始化容量 ≥ 源集合 size
- 极端情况(如合并多个大列表),可先计算总大小,再新建目标 List 并 ensureCapacity
- 避免链式调用:
new ArrayList().addAll(list1).addAll(list2)—— 这样默认容量 10,极大概率反复扩容
结合业务节奏做分批处理
不是所有场景都适合“一口吃成胖子”。比如实时消息流、分页拉取接口,数据是逐步到达的。这时可按批次预估:
- 单页最多 100 条 → 初始化
new ArrayList(100) - 每 1000 条刷一次库 → 每次新建一个容量为 1000 的 List
- 配合 try-with-resources 或局部变量作用域,让旧 List 尽快被 GC,降低内存压力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











