stringbuilder高效源于避免对象创建和原地操作:string+拼接产生o(n²)中间对象,stringbuilder用单数组o(n)追加;预设容量减少扩容开销;链式调用高效但慎用insert/delete;单线程场景禁用stringbuffer。

Java中用StringBuilder构建字符串,核心就两点:避免无谓的对象创建,控制好内部缓冲区大小。它不是万能的,但对循环拼接、动态组装这类场景,效果立竿见影。
为什么StringBuilder比String拼接快?
String每次用+拼接,都会生成新对象;10次拼接就产生10个中间字符串,全得进垃圾回收队列。StringBuilder只用一个char数组(JDK9后是byte数组),所有操作都在原地进行,不额外分配内存。
- String拼接在循环里是O(n²)时间复杂度,StringBuilder是O(n)
- 尤其当拼接内容来自变量或方法返回值时,String+会反复拷贝,StringBuilder append()只是往数组末尾写入
- 底层调用System.arraycopy做扩容复制,比新建对象+拷贝内容轻量得多
容量设置不当反而拖慢性能
默认初始容量16,看似够用,但实际拼接超长文本时频繁扩容很伤。每次扩容都要申请新数组、复制旧数据,开销不小。
- 预估最终长度,直接指定构造容量:new StringBuilder(256)
- 如果长度不确定,但知道上限,按上限设更稳妥
- 扩容公式是 old * 2 + 2(JDK8+),比如从16扩到34,再扩到70……跳变越少越好
- 调用capacity()可查看当前容量,length()看已用长度,两者差距大说明有冗余空间
链式调用让代码干净,但别滥用insert/delete
append()、reverse()这些方法返回this,支持链式写法,读起来顺,执行也高效。但insert()和delete()涉及数组移动,代价比追加高得多。
- insert(0, "x")每次都在开头插,后面所有字符都要后移,N次操作就是O(n²)
- 同理,delete(0, 1)删首字符,也要整体左移,不如最后用substring()截取
- 真正需要中间修改时,优先考虑先append全部,再用replace()或直接转String处理
单线程场景下,别用StringBuffer
StringBuffer和StringBuilder API几乎一样,唯一区别是前者每个方法都加了synchronized。多线程安全是有代价的——锁竞争会让吞吐量明显下降。
- Web应用里,每个请求通常独占一个StringBuilder实例,根本不需要线程安全
- 只有共享可变字符串对象且跨线程修改时,才考虑StringBuffer
- 若真需并发拼接,更推荐用StringJoiner或Collectors.joining()这类不可变聚合方式
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











