循环内拼接必须用StringBuilder,因String不可变,每次+=都新建StringBuilder和String对象并复制数组,10000次产生上万个临时对象,GC压力大、时间复杂度近O(n²),而StringBuilder复用内部char[],仅末尾toString一次,性能差距可达数千倍。

核心就一条:别在循环里用 + 拼接字符串,改用 StringBuilder(单线程)或 StringBuffer(多线程)。
为什么 + 在循环里很慢?
因为 String 是不可变的。每次 result += i 都不是“修改原字符串”,而是:
- 创建一个新的 StringBuilder(内部 new char[])
- 把旧内容和新内容 append 进去
- 调用 toString() 生成一个全新的 String 对象
- 旧 String 和中间 StringBuilder 对象变成垃圾,等 GC 回收
循环一万次,就可能产生上万个临时对象——内存压力大、GC 频繁、耗时飙升。
怎么改?直接换 StringBuilder
单线程场景下,这是最常用也最高效的写法:
立即学习“Java免费学习笔记(深入)”;
- 提前声明
StringBuilder sb = new StringBuilder(); - 循环中只调
sb.append(i),不创建新对象 - 最后用
sb.toString()得到最终字符串 - 如果预估长度较大(比如拼接上万字符),可初始化容量:
new StringBuilder(64000),避免多次数组扩容
StringBuffer 和 StringBuilder 选哪个?
关键区别是线程安全:
- StringBuilder:方法没加锁,性能高,适合方法内局部变量、单线程逻辑
-
StringBuffer:所有 public 方法都带
synchronized,能保证多线程并发 append 不出错,但性能比 StringBuilder 低 10%–15% - 除非明确要被多个线程共享并修改,否则一律优先选 StringBuilder
编译器优化能救场吗?
Java 编译器(javac)对形如 "a" + "b" + "c" 的字面量拼接会直接优化成 "abc";JVM 也可能对简单表达式做运行时优化。
但这些优化不覆盖变量参与的循环拼接。比如 str += s(s 是变量)、或 for 循环里的 +=,JVM 不会帮你换成 StringBuilder——必须手动改。



















