主动预估并设置 stringbuilder 初始容量是最高效扩容控制方式;capacity 是底层数组长度,length 是当前字符数,仅当 length+新增≤capacity 时 append 不扩容;默认容量 16 常不足,应按模板总长或集合累加长度加余量初始化,或用 ensurecapacity 动态补足,复用时优先 setlength(0) 而非新建实例。

直接控制扩容节奏,比依赖默认自增更高效。StringBuilder 的“自动扩容”不是优化手段,而是兜底行为;真正规避频繁堆分配,靠的是主动预估 + 合理初始化,让扩容尽量不发生。
理解 capacity 和 length 的区别
capacity() 返回底层数组长度(已分配的堆空间),length() 返回当前字符数(已用空间)。只要 length() + 新增字符数 ≤ capacity(),append 就不会触发扩容。默认构造容量是 16,但多数业务拼接结果远超这个值,一上来就注定要扩容。
按需设置初始容量,避开前几次扩容
初始化时显式传入合理值,是最简单有效的干预方式:
- 拼固定模板:例如日志格式
"[{}][{}]: {}"+ 用户ID(最长32)+ 方法名(最长64)+ 消息体(预估512),总长 ≈ 3 + 32 + 3 + 64 + 3 + 512 = 617,再加 10% 余量 → 设为new StringBuilder(680) - 拼集合内容:遍历一次
List<string></string>累加所有str.length(),再向上取整到最近的 2 的幂(如 950 → 1024) - 用字符串初始化:
new StringBuilder("HTTP/1.1 200 OK\r\n")实际容量 = 18 + 16 = 34,适合后续追加少量头字段
运行中动态补足,不依赖“猜得准”
对长度波动大的场景,可在关键节点调用 ensureCapacity(int minCapacity):
- 它只在当前 capacity 不足时才扩容,多次调用无副作用
- 比如解析 CSV 行前,先算出本行预估长度,再调用
sb.ensureCapacity(lineEstimate) - 避免在循环内反复判断,把预留动作集中到数据进入点
复用实例 + 清空技巧,省掉重复分配
每次 new StringBuilder() 都会分配新 char[](默认 16 字节),高频调用下开销累积明显:
- 方法内单次拼接:局部变量 new 一次,用完即弃,没问题
- 线程内高频复用:用
ThreadLocal<stringbuilder></stringbuilder>缓存,首次 get 时初始化,后续直接setLength(0)重置逻辑长度——不释放底层数组,也不触发 GC - 注意:
setLength(0)比new StringBuilder()轻量得多,且保留已有 capacity
扩容公式(old × 2 + 2)本身无法绕过,但你可以让它根本不用启动。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











