循环拼接字符串应使用 stringbuilder 并复用实例,预估容量避免扩容,单线程下禁用 stringbuffer,高频场景可用 threadlocal 复用并清空。

循环中拼接字符串,直接用 += 是性能黑洞;换成 StringBuilder 并规范使用,能将时间复杂度从 O(n²) 降到 O(n),大幅减少临时对象和 GC 压力。
循环外初始化,循环内只 append
别在循环里每次 new StringBuilder(),也别每轮都 toString() —— 这会让优化失效。
- 在 for/while 开始前创建实例,复用同一个对象
- 循环体内只调用
append(),支持链式写法:sb.append("ID:").append(id).append(", ").append(name) - 所有拼接完成后,只调用一次
toString()获取最终字符串
预估容量,避免频繁扩容
默认容量 16,拼接稍多就触发数组复制(扩容公式:旧容量 × 2 + 2),开销明显。
- 按“元素数 × 平均长度 + 分隔符总长 + 余量(10%~20%)”粗略估算
- 例如拼接 500 条日志,每条约 40 字符,加换行符:可设
new StringBuilder(500 * 40 + 500 + 1000)≈21500 - 不确定长度但数据量大时,宁可设 4096 或 8192,也比反复扩容强
避开常见陷阱
写对了方向,细节错了照样拖慢性能。
- 别混用
+和append(),如sb.append("a" + "b")—— 编译器会先生成临时 StringBuilder,白费预分配 - 不要在多线程间共享同一实例;单线程场景无需
StringBuffer,它带同步锁反而更慢 - 需要去尾逗号或换行符时,用
sb.delete(sb.length()-1, sb.length()),比 substring 更高效
高频调用时考虑轻量复用
如果方法被频繁调用(如 Web 接口处理),每次 new 仍有对象分配开销。
- 局部复用:方法内声明,循环前创建,用完即弃,作用域清晰
- 线程级复用:用
ThreadLocal<stringbuilder></stringbuilder>缓存,每次取用后调用setLength(0)清空 - 避免 static 共享:并发修改会导致字符错乱甚至数组越界异常
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











