string在循环中拼接极慢,因每次“+=”都新建stringbuilder、append后tostring,生成大量临时对象和垃圾,时间复杂度达o(n²);stringbuilder通过可变char[]数组复用内存,仅末次创建string,性能提升数千倍。

循环内拼接必须用 StringBuilder,单次或少量拼接用 String 完全没问题——这不是经验之谈,而是由底层机制决定的硬性边界。
为什么 String 在循环里拼接特别慢?
每次用 += 或 + 拼接,JVM 实际执行三步:
- 新建一个
StringBuilder对象(默认容量 16) - 把原字符串和新内容依次
append - 调用
toString()创建新String,旧对象变成垃圾
循环 10000 次,就生成约 10000 个中间 String 和同等数量的临时 StringBuilder。CPU 大量时间花在数组复制和 GC 回收上,时间复杂度接近 O(n²)。
StringBuilder 高效的关键点
它内部维护一个可变的 char[] 数组,所有操作都在原数组上进行:
- 初始容量足够时:零对象创建、零数组拷贝
- 容量不足时:仅扩容一次(通常翻倍),再拷贝一次原内容
- 最终只调用一次
toString(),生成最终结果
实测 10 万次数字拼接:String += 耗时约 18 秒,StringBuilder.append() 仅需 5 毫秒。
怎么初始化 StringBuilder 才真正高效?
光换类不够,构造方式直接影响性能:
- 避免
new StringBuilder():默认 16 字符容量,小循环就频繁扩容 - 预估长度更稳:
new StringBuilder(2048)或new StringBuilder(base.length() + expectedSize) - 局部变量优先:方法内新建、用完即弃,线程安全又无锁开销
- 慎用
toString()后长期持有:它引用整个内部数组;若只需子串,改用substring()或new String(char[], offset, len)
StringBuffer 真的更稳妥吗?
不是。它和 StringBuilder 功能几乎一样,但每个 public 方法都加了 synchronized。单线程下纯属锁竞争和上下文切换开销,实测比 StringBuilder 慢 1.5–2 倍。真需要多线程共享,用 ThreadLocal<stringbuilder></stringbuilder> 更轻量、更可控。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











