java字符串拼接性能问题核心在于执行上下文和对象创建频次:循环内用+会导致o(n²)复杂度和gc压力,应优先使用预设容量的stringbuilder;单次拼接或编译期可优化场景用+无妨,多线程下避免stringbuffer而推荐threadlocal。

Java 中字符串连接操作对性能的影响,核心不在“拼接”本身,而在执行上下文和对象创建频次。String 不可变,每次拼接都产生新对象;问题不是“用了+”,而是“在哪儿、多少次用了+”。
循环内用 + 或 += 会严重拖慢程序
每次 s += "x" 实际等价于:
- 新建一个
StringBuilder(默认容量 16) - 把旧字符串和新内容
append进去 - 调用
toString()生成新String,旧字符串变成垃圾
循环 10,000 次,就创建约 10,000 个 StringBuilder 和同等数量的中间 String,GC 压力陡增,时间复杂度接近 O(n²)。实测耗时可能达十几秒,而 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)或new StringBuilder(base.length() + expectedSize)
别误用 StringBuffer
StringBuffer 和 StringBuilder 功能一致,唯一区别是前者所有 public 方法加了 synchronized。单线程下纯属锁开销,实测慢 1.5–2 倍。多线程共享拼接结果时,优先考虑 ThreadLocal<stringbuilder></stringbuilder>,轻量又可控。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











