循环中string+=拼接性能极差,因每次创建新对象导致o(n²)时间复杂度和gc压力;应改用预估容量的stringbuilder.append(),或根据场景选用string.join、stringjoiner、slf4j占位符、preparedstatement等更优方案。

在循环里用 String += 拼接,表面看简洁,实则埋下严重性能隐患——每次拼接都新建对象,1000次循环可能生成上千个临时字符串,GC压力陡增,响应延迟肉眼可见。
为什么循环中String拼接特别慢
String 是不可变对象,s += "x" 并不是往原字符串末尾加内容,而是:创建新 StringBuilder → append 原字符串 → append 新内容 → toString 生成新 String → 丢弃旧对象。循环每轮都重复这套流程。
- 时间复杂度接近 O(n²):第 i 次拼接要复制前 i−1 个字符
- 内存爆炸:10000 次拼接 ≈ 10000 个中间 String 对象,全进堆,等着 GC 扫描回收
- 编译器不优化循环体内的 +:它无法预判迭代次数,只能每轮都 new StringBuilder()
必须换成 StringBuilder 的典型场景
只要满足以下任一条件,就该立即重构为 StringBuilder:
- for / while 循环内执行字符串拼接(哪怕只拼 3 次)
- 组装日志消息,例如
"user=" + uid + ", action=" + op - 动态构建 JSON、XML、SQL 或 HTML 片段
- 模板渲染中多次插入变量值
StringBuilder 正确用法要点
光换类名不够,关键在初始化和调用方式:
- 构造时预估容量,比如拼接 500 个平均长度 8 的字符串,写
new StringBuilder(4000),避免多次扩容复制 - 全程只用
append(),不要在循环里反复调用toString() - 链式调用更高效:
sb.append("id:").append(id).append(", name:").append(name) - 单线程场景选 StringBuilder;多线程且需共享实例,才考虑 StringBuffer
其他更优替代方案
不是所有拼接都要手写 StringBuilder:
- 拼集合或数组?直接用
String.join(",", list),语义清晰、自动处理 null - 带分隔符+前后缀?用
StringJoiner,比手动拼更安全 - 日志拼接?改用 SLF4J 占位符:
log.info("req={}, status={}", reqId, status),避免无意义构造 - SQL 拼接?一律走 PreparedStatement 参数绑定,既防注入又复用执行计划
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











