String不可变且线程安全,适合读多写少;StringBuilder可变、非线程安全,单线程拼接性能远超String,适用于循环拼接、动态文本构建等场景。

String 和 StringBuilder 的核心区别在于「是否可变」和「是否线程安全」,这直接决定了它们的性能表现和适用场景。简单说:String 适合读多写少、内容固定的场合;StringBuilder 是单线程下高频拼接的首选,性能远超 String。
不可变 vs 可变:底层行为完全不同
String 是不可变类(immutable),所有修改操作(如 concat、substring、+ 拼接)都会新建对象,原字符串不受影响。而 StringBuilder 底层是一个可扩容的 char[](JDK9+ 是 byte[]),所有 append、insert、delete 都在原数组上操作,不产生额外对象。
- String 每次拼接都触发一次 new String(),循环 10000 次 ≈ 创建 10000 个临时对象,加重 GC 压力
- StringBuilder 默认初始容量 16,超出时自动扩容(新容量 = 原容量 ×2 + 2),复用同一对象
- String 的不可变性带来线程安全、哈希缓存、字符串池复用等优势,但代价是写操作开销大
性能差距:不是“稍微快点”,而是数量级差异
在单线程字符串拼接场景中,StringBuilder 的吞吐量通常是 String 的几十倍。比如拼接 10 万个短字符串:
- 用 String +=:可能耗时数百毫秒,伴随频繁 Full GC
- 用 StringBuilder.append():通常在几毫秒内完成,内存分配极少
- 编译器对 String 字面量拼接有优化(如 "a" + "b" 直接转为常量),但变量参与的拼接(如 s += i)仍会编译成 StringBuilder 调用——所以手动用 StringBuilder 更可控、更高效
什么时候该用 StringBuilder?关键看这三点
不必纠结“是不是一定要换”,记住三个典型信号:
立即学习“Java免费学习笔记(深入)”;
- 代码里出现循环内使用 += 或 concat() 拼接字符串
- 构造日志、JSON、SQL、HTML 等动态文本,且拼接步骤超过 3 步
- 方法返回前需组装较长字符串,且中间变量只被当前线程使用
满足任一条件,就该把 String 拼接换成 StringBuilder。例如:
// ❌ 低效写法
String result = "";
for (int i = 0; i
result += "item" + i + ",";
}
// ✅ 推荐写法
StringBuilder sb = new StringBuilder();
for (int i = 0; i
sb.append("item").append(i).append(",");
}
String result = sb.toString();
别混淆 StringBuffer:它不是“升级版”
StringBuffer 和 StringBuilder API 几乎一致,但 StringBuffer 所有方法都加了 synchronized。这意味着:
- 多线程环境下可安全共用同一个 StringBuffer 实例
- 单线程下,同步锁反而拖慢性能(实测比 StringBuilder 慢 10%–20%)
- 除非明确需要跨线程共享并修改同一字符串缓冲区,否则不用 StringBuffer
日常开发中,绝大多数字符串拼接都在单线程内完成,StringBuilder 就是更轻、更快、更直接的选择。



















