循环拼接字符串必须用stringbuilder而非+=,因string不可变会导致大量临时对象和频繁gc;正确做法是循环外初始化、循环内append、循环后tostring,并预设合理容量。

循环里拼接字符串,别用 += 或 +,直接用 StringBuilder——这是 Java 中最容易见效、也最常被忽视的性能优化点。
为什么循环里必须用 StringBuilder?
String 是不可变的。每次写 result += "item" + i,JVM 都会隐式创建一个 StringBuilder → append → toString,生成一个新 String 对象。循环 1 万次,就可能产生上万个短命对象,堆内存飙升,Young GC 频繁触发。
StringBuilder 内部维护可变字符数组,append() 只是往末尾填数据,扩容按需进行(默认 16,不够时翻倍),没有中间对象开销。
正确写法:三步不能错
-
循环外初始化:
StringBuilder sb = new StringBuilder(2048);—— 别放在 for 里反复 new -
循环内只 append:支持字符串、数字、布尔等类型,链式调用更高效,如
sb.append("ID: ").append(id).append("\n") -
循环后一次性 toString:
String output = sb.toString();—— 这步必须有,且不能在循环里反复调用
预设容量:省掉多次扩容的关键
扩容公式是 新容量 = 旧容量 × 2 + 1,每次扩容都要复制整个数组。频繁扩容会让性能断崖下跌。
- 能估算总长就显式设置:比如拼接 500 条日志,每条平均 60 字符 + 换行符,预估
500 × 60 + 500 ≈ 30500,写new StringBuilder(30500) - 不确定长度但数据量大,宁可高估:如设
4096或8192,比默认 16 更稳妥 - 避免用
ensureCapacity()补救——它只扩不缩,还多一次方法调用
哪些情况不用硬套 StringBuilder?
- 单行拼接,如
"User " + user.getName() + " logged in":编译器自动优化,代码更简洁 - 拼接次数 ≤ 3 次,且内容简单:手动写 StringBuilder 反而增加冗余
- 只是把 List 拼成逗号分隔串:
String.join(",", list)更安全高效,还自动跳过 null - 多线程共享同一实例:绝对禁止!应每个线程独立创建,或改用 StringBuffer(但有同步开销)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











