java中字符串拼接应优先使用stringbuilder而非+或string.concat(),需预估容量避免扩容、循环中只append最后tostring、高频调用时考虑局部复用或threadlocal缓存,单线程场景不用stringbuffer。

在Java中,频繁拼接字符串时直接用+或String.concat()会导致大量临时对象创建,严重拖慢性能。循环中尤其明显——每次拼接都生成新String对象,触发GC压力。用StringBuilder替代,能显著提升效率,但必须注意初始化容量和复用方式。
循环前预估容量,避免动态扩容
StringBuilder底层是字符数组,扩容需复制旧数组,代价不小。若提前知道最终字符串大致长度(比如拼接100个平均20字符的字符串),就应在构造时指定初始容量:
- 不推荐:
new StringBuilder()(默认16字符,极易触发多次扩容) - 推荐:
new StringBuilder(2000)(预留足够空间,基本免扩容) - 估算技巧:按元素数 × 平均单条长度 × 1.2 留点余量
循环内只调用append(),别反复toString()
常见误区是在循环里每轮都sb.toString()——这不仅浪费CPU,还让后续append()失去意义。正确做法是全程只操作StringBuilder对象,最后一次性转成String:
- 错误写法:
for (...) { result = sb.append(...).toString(); } - 正确写法:
for (...) { sb.append(...); } String finalStr = sb.toString(); - 若需中间结果,考虑用
sb.substring()或另建临时StringBuilder,而非toString()
避免在循环外重复创建StringBuilder实例
如果方法被高频调用(如Web请求处理),每次都new StringBuilder()仍会带来对象分配开销。可考虑两种优化:
- 局部复用:方法内声明,循环前创建,循环后立即使用,作用域清晰
- 线程安全场景:用
ThreadLocal<stringbuilder></stringbuilder>缓存实例,避免同步开销 - 不建议全局静态共享:多线程并发修改会出错,且难以控制生命周期
对比StringBuffer?多数场景不必
StringBuffer所有方法都加了synchronized,适合多线程共享拼接。但单线程循环中,它的同步锁纯属冗余开销:
- 性能测试表明:
StringBuilder比StringBuffer快约15%~30% - 除非明确需要跨线程共用同一个拼接器,否则一律选
StringBuilder - 多线程各自独立拼接?每个线程用自己
StringBuilder,更轻量也更安全
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











