String拼接在循环中很慢,因为String不可变,每次“+=”都创建新对象,导致频繁内存分配和GC压力增大。

在循环中频繁使用 String 拼接(如 str += "xxx")会导致严重性能问题,根本原因是 String 是不可变对象,每次拼接都会创建新对象,引发大量临时字符串和内存分配,GC 压力陡增。
为什么 String 拼接在循环里很慢?
Java 中每个 String 实例一旦创建就不能修改。例如:
String s = "";
for (int i = 0; i < 10000; i++) {
s += "a"; // 每次都 new String(...),旧字符串被丢弃
}
执行 1 万次后,实际生成了约 1 万个中间 String 对象,时间复杂度接近 O(n²),内存占用也线性增长。
推荐替代方案:StringBuilder
StringBuilder 是可变字符序列,内部基于动态数组(char[]),扩容策略合理,适合多次追加场景:
- 初始化时预估容量(避免多次扩容),如
new StringBuilder(1024) - 循环内统一用
append(),最后调用toString()获取结果 - 单线程场景下比
StringBuffer更快(无同步开销)
示例:
StringBuilder sb = new StringBuilder(1024);
for (int i = 0; i < 10000; i++) {
sb.append("a");
}
String result = sb.toString(); // 仅一次对象创建
更现代的选择:StringJoiner 或 String.join()
如果拼接的是已知集合或数组,优先用 JDK 8+ 提供的高阶 API:
-
String.join(",", list):简洁、安全、自动处理 null(转为空字符串) -
StringJoiner:支持前缀、分隔符、后缀,适合构建带格式的字符串 - 流式拼接:
list.stream().collect(Collectors.joining(","))
这些方法底层仍使用 StringBuilder,但封装了逻辑,不易出错且语义清晰。
特殊情况处理建议
某些场景看似是循环拼接,实则可优化思路:
- 日志拼接:改用占位符(如 SLF4J 的
log.info("user={}, age={}", user, age)),避免无谓构造 - SQL 拼接:改用 PreparedStatement + 参数绑定,既防注入又提升复用性
- 模板类内容:考虑使用
MessageFormat或轻量模板引擎(如 StringTemplate)
不复杂但容易忽略。


















