高效拼接字符串的关键在于容量预设、实例复用和链式调用:需显式指定初始容量避免扩容,循环外创建并复用实例,用append链式调用绕过临时对象,仅在必要时调用toString()。

高效拼接字符串的关键不在“用了 StringBuilder 没”,而在“容量设没设、实例复用没、链式调用对不对”。默认构造、循环内新建、混用 + 号,这三类操作会直接抵消 StringBuilder 的全部优势。
预估初始容量,避开频繁扩容
StringBuilder 底层是 char 数组,默认容量仅 16。一旦超出,就会按 旧容量 × 2 + 2 扩容,并复制整个数组——这是性能损耗的主要来源。
- 能估算总长度就显式指定:拼接 800 个平均 30 字符的用户名,加 799 个逗号,总长约 800×30 + 799 = 24799 → 写
new StringBuilder(25000) - 不确定但数据量大(如日志缓冲、CSV 导出),宁可高估:设
4096或8192,避免扩容超过一次 - 别靠
ensureCapacity()补救——它只扩不缩,还多一次方法调用开销
复用实例,别在循环里反复 new
每次 new StringBuilder 都会分配新数组,产生短期对象,加重 GC 压力。高频拼接场景必须控制生命周期。
- 单次任务:循环外创建,循环内只
append(),最后toString() - 多次独立拼接:用
sb.setLength(0)清空内容,比新建快得多(保留底层数组) - 线程池中使用:配合
ThreadLocal<StringBuilder>隔离复用,安全又轻量 - 绝对禁止 static 共享或跨线程传同一实例——可能丢字符、乱序、甚至抛异常
链式调用 append,绕过隐式装箱和临时字符串
append() 返回自身,支持连续调用;且对基本类型、boolean、char[] 等都有重载,内部直接写入字符,不经过 String.valueOf()。
立即学习“Java免费学习笔记(深入)”;
- 推荐:
sb.append("id:").append(userId).append(", active:").append(active) - 避免:
sb.append("id:" + userId)(编译器先建临时 StringBuilder)、sb.append(String.valueOf(userId))(多一次字符串创建) - 拼接 char 数组片段时,用
append(char[], start, len),避免子串截取开销 - 遇到 null 值需明确处理:默认
append(null)写入 "null" 字符串;业务不允许时,提前判空或用Objects.toString(x, "")
toString() 时机要精准,别早调也别漏调
toString() 是创建最终 String 对象的唯一出口,但它会复制全部字符。调太早浪费内存,调太晚拿不到结果。
- 只在真正需要字符串时才调用——比如返回给 API、写入文件、生成响应体
- 循环中禁止反复调用:每次都是 O(n) 复制,性能断崖下跌
- 部分框架(如 SLF4J 日志、Jackson 序列化)支持 CharSequence,可直接传 StringBuilder 实例,跳过
toString() - 调完
toString()后,StringBuilder 仍可继续用,但底层数组已不再共享(新 String 持有独立副本)



















