应使用 StringBuilder 替代 String 循环拼接,因其维护可扩容字符数组,避免频繁创建对象和复制;单线程选 StringBuilder 而非 StringBuffer;分隔符拼接优先用 StringJoiner;编译器仅优化字面量合并,不优化循环内拼接。

String 的不可变性本身不能被“优化”,它是 Java 的设计契约,也是安全与缓存机制的基础。真正要做的,是绕过不可变性带来的拼接开销——用可变的容器来累积内容,最后一次性生成 String。核心思路就一条:别在循环里用 +=,改用 StringBuilder 做累积,只在最终需要时调用 toString()。
StringBuilder 是绕过不可变性的标准解法
它不修改任何 String 对象,而是自己维护一个可扩容的字符数组(JDK 9+ 是 byte[]),所有 append() 都直接写入这个数组,完全避开新建对象和复制旧内容的过程。
- 默认初始容量是 16,但若能预估最终长度(比如拼 500 个平均 30 字符的字段),建议显式指定:
new StringBuilder(500 * 30 + 500); // +500 留给分隔符
避免多次扩容(扩容策略通常是
oldCapacity * 2 + 2),每次扩容都要复制原数组,白白耗 CPU。 - 单线程场景下始终选
StringBuilder,不是StringBuffer;后者加锁,性能低 10%~15%,纯属冗余。
分隔符拼接优先用 StringJoiner
当拼接需带固定分隔符(如逗号)、前缀(如 [)、后缀(如 ])时,StringJoiner 比手动用 StringBuilder 拼分隔符更清晰、不易出错:
立即学习“Java免费学习笔记(深入)”;
StringJoiner sj = new StringJoiner(",", "[", "]");
sj.add("a").add("b").add("c"); // → "[a,b,c]"它底层其实也用 StringBuilder,但封装了边界逻辑,代码意图更明确。
编译器优化有边界,别依赖它
- 字面量拼接
"a" + "b" + "c"会在编译期合并,没问题; - 但
s += "x"在循环里,每轮都会新建 StringBuilder 和 String,编译器不会跨迭代优化; - 运行时变量拼接如
a + b + c,JVM 会自动转成new StringBuilder().append(a).append(b).append(c).toString(),但这只限单条语句,不解决循环问题。
少量拼接不用强求 StringBuilder
方法内拼 2~3 个变量(如 log("user=" + id + ", action=" + op)),JVM 通常已自动优化,手动换 StringBuilder 反而增加代码噪音。重点盯住:循环体、批量生成、日志组装、SQL 构建、模板渲染等高频/大数据量场景。



















