应复用 stringbuilder 实例、预估并设置合理初始容量、避免循环内新建或频繁 tostring;根据场景选 stringbuilder(单线程)、stringbuffer(多线程)或 stringjoiner(带分隔符)。

直接用 StringBuilder 替代循环里的 + 拼接,能避免大量临时 String 对象,但光“用了”还不够——关键在初始化方式、容量控制和生命周期管理。
把 StringBuilder 提到循环外复用
每次在循环里 new StringBuilder(),等于重复分配底层数组、重置计数器,完全失去复用价值。正确做法是:在方法开头或作用域起始处创建一次,全程 append,最后 toString。
- ❌ 错误写法:循环内反复 new,每次生成新数组(默认容量 16)
- ✅ 正确写法:一次初始化,多次 append,仅最终调用一次 toString()
- ⚠️ 注意:不要在每次 append 后调用 toString(),否则又会生成新 String,抵消优化效果
预估并设置合理初始容量
StringBuilder 底层是 char(或 byte)数组,扩容靠 System.arraycopy() 复制全部已有内容,开销是 O(n)。频繁扩容比多占点内存更伤性能。
- 静态拼接(如模板 + 几个变量):算出模板长度 + 所有变量最大可能字符数,再加 10%~15% 余量
- 集合拼接(如 List
):先遍历求和所有 str.length(),再向上取整到 2 的幂(如 3000 → 4096) - 不确定但有上限:设为 128、512 或 4096 等常见缓冲值,比默认 16 更稳
- 运行时补救:可用
sb.ensureCapacity(expectedTotal)主动预留,只在不足时生效
避免无意义的内存浪费
容量(capacity)不是已用长度(length),而是已分配的总缓冲区大小。设得过大,虽不触发扩容,但白白占用堆内存,小对象增多反而加重 GC 压力。
- 检查
sb.capacity() - sb.length()差值:长期接近 0 表示预留严重不足;若差值达 length 的几十倍,说明预估过大 - 超大文本(MB 级)别硬扛:考虑用
StringJoiner、BufferedWriter或流式分块处理 - 高频短任务可复用:通过 ThreadLocal 缓存实例,避免反复 new 和初始化数组
区分场景选对工具
StringBuilder 不是万能解药,要结合语义和并发需求选择:
- 单线程拼接 → 用 StringBuilder(轻量、快)
- 多线程共享拼接 → 改用 StringBuffer(同步安全,但有锁开销)
- 带分隔符的集合拼接 → 优先
StringJoiner或Collectors.joining()(语义清晰,底层仍用 StringBuilder) - 纯常量拼接(如
"a" + "b" + "c")→ 编译期自动优化,无需改写
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











