选对扩容策略的关键是平衡“少扩容”和“少浪费”,优先采用1.5倍扩容公式(新容量=旧容量+旧容量>>1),结合业务预估初始容量、高频写入前调用ensurecapacity,并在空闲率超70%时考虑trimtosize缩容。

不确定集合大小时,选对扩容策略的关键是平衡“少扩容”和“少浪费”——不能盲目翻倍,也不该每次只加1个位置。核心思路是:用渐进式增长降低扩容频次,同时结合业务特征做合理预估。
优先采用 1.5 倍扩容公式
这是 JDK ArrayList 经过长期验证的工业级策略,计算简单且空间利用率高:
- 新容量 = 旧容量 + (旧容量 >> 1),等价于 ×1.5(如 10→15,15→22,22→33)
- 相比 ×2:节省约 25% 内存,尤其在中等规模(几百到几千)时效果明显
- 相比 +1 或 +10:大幅减少扩容次数,避免 O(n²) 时间退化
- 注意兜底:若计算结果仍小于所需最小容量(如 addAll 时一下要塞 1000 个),直接取 minCapacity
- 防溢出:newCapacity > MAX_ARRAY_SIZE 时,设为 Integer.MAX_VALUE
根据场景预估初始容量,比纯靠扩容更高效
即使无法精确知道最终大小,也能借助业务线索缩小范围:
- 日志收集:单次请求最多生成 20 条日志 → 初始设 32
- 分页查询:每页 20 条,最多查 5 页 → 初始设 100
- 表单提交:前端校验最多允许填 15 个附件 → 初始设 16
- 不确定但有上限:比如“用户最多上传 100 张图片”,就直接 new ArrayList(100)
对高频写入或批量操作,主动调用 ensureCapacity
当循环添加前已知总数(哪怕只是估算),提前预留空间能跳过多次中间扩容:
- 例如解析 CSV 文件,预读前 10 行发现平均每行 8 列 → 后续每行 add 时先 ensureCapacity(8)
- 或批量导入:list.ensureCapacity(expectedCount);再 for 循环 add,性能提升可达 2~3 倍
- 注意:过度预估(如设 10 万却只存 100)会造成内存闲置,需结合监控数据反向优化
缩容不是必须的,但空闲率过高时值得考虑
如果集合长期只用到不到 30% 的已分配容量,且后续不会再增长,可手动缩容释放内存:
- 调用 trimToSize() 让数组长度收缩到当前 size
- 或自定义 shrinkIfOverProvisioned(float threshold),如 threshold = 0.3f
- 慎用于频繁增删场景——缩容后再扩容反而得不偿失
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











