Java 中 String 的字符串连接操作如何影响性能
Java字符串拼接的性能关键在于执行上下文。循环内使用“+”会反复创建StringBuilder和临时String,导致性能剧降;单次拼接则编译器可优化。短拼接用concat(),多个分隔符用String.join,高频场景应预设容量的StringBuilder,避免使用StringBuffer。
Ja va 字符串拼接的性能问题,其实没那么玄乎。说到底,决定性能的不是用了“+”号还是“concat”方法,而是代码在什么上下文里跑、每个语句执行了多少次。String 对象不可变,每次拼接都意味着新对象的诞生——这本身不是问题,问题在于“在循环里狂拼”,那才是灾难。
说实话,很多开发者一听到“字符串拼接”就说“别用+”,这个结论太绝对了。真正该警惕的场景,下面会逐一拆开来看。
循环内用 + 或 += 会严重拖慢程序
你以为写了一句 s += "x",实际上 Ja va 编译器在背后干了三件事:先 new 一个 StringBuilder(默认容量 16),然后调用 append 把旧字符串和新内容拼上,最后 toString 生成新 String。旧字符串立马变成待回收的垃圾。循环 1 万次,就创建 1 万个 StringBuilder 和 1 万个中间 String——GC 不爆才怪,时间复杂度直接奔着 O(n²) 去了。
实测过吗?循环 1 万次 + 拼接,耗时十几秒起步;换成预先指定容量的 StringBuilder,几毫秒搞定。这不是语法之争,是量变引起质变。
单次拼接用 + 完全没问题
编译器对静态或简单变量的拼接做了深度优化,很多人不知道这一点:
"a" + "b" + "c"→ 编译期直接合入常量池,运行时零开销prefix + value + suffix→ JDK 9+ 多数情况会编译成高效字节码,或者自动转成 StringBuilder 链式调用- 日志场景要特别注意:写
log.debug("id=" + id)就算日志级别关闭,拼接仍然执行。该用占位符就用占位符:log.debug("id={}", id)
所以,别再见到“+”就一棍子打死。关键看它在哪、拼多少次。
选对工具比纠结语法更重要
与其问“哪个方法更快”,不如问“哪个工具更适合当前场景”:
- 只拼两个字符串且确定不在循环里 →
.concat()更好,底层直接数组拷贝,没有额外对象创建 - 拼多个字符串且需要分隔符 →
String.join("-", list),代码简洁,内部已用 StringBuilder 实现 - 格式化需求强(日期、金额) →
String.format()方便,但别放进高频执行路径里 - 真正频繁拼接,尤其循环或条件分支多次执行 → 必须上 StringBuilder,而且建议预设容量:
new StringBuilder(2048)或根据预期长度估算
别误用 StringBuffer
StringBuffer 和 StringBuilder 功能一模一样,唯一的区别是前者每个 public 方法都加了 synchronized 关键字。单线程下用 StringBuffer,纯属给自己加锁开销——实测比 StringBuilder 慢 1.5 到 2 倍。多线程场景下如果要共享拼接结果,也别直接用 StringBuffer,更轻量的方案是 ThreadLocal,各线程各自拼、最后再汇总。
工具从来不是越复杂越好,而是越对症越好。










































