关键在于预估总长并合理设置初始容量,而非盲目使用capacity和ensurecapacity;capacity是底层数组长度,length是实际字符数,扩容触发条件为length+新增字符数>capacity,推荐用带参构造器一次性设对容量。

关键不是“用不用 capacity 和 ensureCapacity”,而是“预估准、设得对、验得实”。默认容量 16 在多数业务场景下形同虚设,真正影响性能的是底层数组反复复制——而这两者正是控制扩容节奏的核心工具。
先搞清 capacity 和 length 的区别
capacity() 返回的是内部 char[] 数组的长度,即已分配的堆空间大小;length() 是当前实际字符数。只有当 length() + 新增字符数 > capacity() 时,append 才会触发扩容。
- 新建空 StringBuilder:capacity = 16
- 用字符串初始化:
new StringBuilder("abc")→ capacity = 3 + 16 = 19 - 扩容公式通常是
old × 2 + 2(如 16→34→70→142),每次都要 System.arraycopy 整个数组
预估总长,一次性设置初始容量最高效
如果拼接结构固定或长度可估算,直接用带参构造器,比事后调 ensureCapacity 更简洁、更少开销:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 拼日志模板:
"[{}][{}]: {}"+ 用户ID(32) + 方法名(64) + 消息体(512) ≈ 617,加 10% 余量 →new StringBuilder(680) - 拼集合:用
list.stream().mapToInt(String::length).sum()算出原始长度,再加逗号、换行等固定开销 - 向上取整到 2 的幂更友好(如 3800 → 4096,7200 → 8192),JVM 内存分配效率更高
动态场景下,用 ensureCapacity 集中补足,别在循环里乱调
当长度波动大、无法在创建时精准预估时,可在数据进入前的关键节点调一次 ensureCapacity:
- 解析 CSV 行前,先算该行最大可能长度(含所有字段+分隔符+换行符),再调
sb.ensureCapacity(lineEstimate) - 批量生成 JSON 前,按字段数 × 平均长度 + 预留缓冲统一预设
- 绝对不要写
if (sb.capacity() 在 for 循环里——append 内部已有扩容逻辑,重复判断纯属浪费
复用实例时,setLength(0) 比 new 更轻量
高频拼接(如日志收集、模板渲染)应避免每次都 new StringBuilder:
- 用 ThreadLocal 缓存固定容量实例(如 1024),每次复用前调
sb.setLength(0)——不清空底层数组,也不触发 GC - 若后续内容明显变长,可在 setLength(0) 后再调一次 ensureCapacity 更新容量
- 对比:new StringBuilder() 每次都分配新 char[](默认 16 字节),高频下堆压力和 GC 明显上升
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










