应优先使用stringbuilder而非+号拼接字符串,因其通过可扩容char数组原地修改避免频繁创建临时string对象,大幅降低内存开销与gc压力;尤其适用于循环拼接、日志组装、sql生成等高频场景。

Java里拼接字符串,别一上来就用+号。尤其在循环里、日志组装、SQL生成这类场景,String的不可变性会悄悄拖垮性能——每次拼接都新建对象,堆里堆满临时字符串,GC跟着忙个不停。真正高效的做法,是用StringBuilder,它不造新对象,只在一块内存上反复改。
为什么String拼接慢?底层在干啥
String类被final修饰,内部char[] value也是final的。这意味着一旦创建,内容就不能动。比如写:
String s = "a"; s += "b"; s += "c";
表面看是在追加,实际执行了三步:
→ 创建" a "对象
→ 创建" ab "对象(复制"a"再加"b")
→ 创建" abc "对象(复制"ab"再加"c")
前两个对象立刻变成垃圾,等GC回收。1000次循环?就是1000个中间字符串。
StringBuilder怎么做到又快又省
它本质是个“可伸缩的字符数组容器”。初始化时默认分配16个字符的底层数组,后续append、insert、delete都在这个数组上原地操作:
- 容量不够时自动扩容(通常是当前容量×2+2),避免频繁重新分配
- 所有修改方法直接操作
char[],不生成新对象 - 最终调用
toString()才一次性生成最终String实例
相当于把1000次“建房—拆房—再建房”,换成“一栋楼里不断装修”,省时间也省建材。
怎么用才真正发挥优势
光用StringBuilder还不够,几个关键点直接影响效果:
-
预估初始容量:如果知道最终字符串大概多长,构造时指定容量,避免多次扩容。例如拼接100个长度为20的字符串,直接
new StringBuilder(2000) -
链式调用:
sb.append("a").append(123).append(true)比分开写更简洁,也少一次变量读取 - 避免无谓的toString():不要在循环里每拼一次就转成String,等全部拼完再转
-
别在多线程里共用同一个实例:它不是线程安全的,并发修改可能丢数据。真要多线程,选
StringBuffer或换思路(如每个线程自己new一个)
什么情况其实不用StringBuilder
并不是所有拼接都要优化。编译器对+做了不少聪明事:
- 纯字面量拼接(如
"a" + "b" + "c")会在编译期直接合并成"abc" - 少量拼接(比如方法内拼2~3个变量),JVM通常会自动用
StringBuilder优化,手动写反而啰嗦 - 只拼一次、且对象不多的场景,性能差异几乎感知不到
重点盯住那些循环体里、IO操作前、高频调用路径上的字符串组装——那里才是StringBuilder该出手的地方。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











