必须用stringbuilder的场景包括:循环内高频拼接(≥5次且每次超10字符)、跨方法分散拼接、已知长度可预设容量、需动态插入/删尾/替换;初始化应显式指定容量避免扩容开销;优先链式append,禁用循环内string+=,单线程选stringbuilder,多线程共享才考虑stringbuffer,严禁static共享。

直接用 StringBuilder 替代循环里的 String +=,性能提升往往能达几十倍——但前提是它真被用在了该用的地方。盲目替换不光没收益,还可能引入线程安全风险或冗余代码。
哪些场景必须用 StringBuilder
不是所有拼接都要换,关键看是否处于高频、可积累的修改路径:
- 循环内拼接,且循环次数 ≥ 5、每次追加内容平均超 10 字符(比如组装日志行、生成 HTML 表格行、拼 SQL WHERE 条件)
- 拼接逻辑分散在多个方法中(如递归生成树形 JSON、模板引擎中嵌套回调填充字段),编译器无法做跨方法优化
- 已知最终长度范围(例如导出 5000 条记录,每条含 80 字符 + 分隔符),可预设容量避免扩容开销
- 需要动态插入、删尾、替换(如用
insert(0, "【"+type+"】")加前缀,或用deleteCharAt(length()-1)去掉末尾逗号)
怎么初始化才不拖慢性能
默认容量 16 很小,频繁扩容会反复复制数组,代价不小:
OpenJDK 24 Windows x64 官方参考实现(24+36),适合 Windows 环境进行 Java 开发、编译、运行和版本兼容性验证。
- 能估算总长就显式指定:比如拼 200 个平均 30 字符的字符串 + 199 个逗号,粗算约 200×30+199 = 6199,可写
new StringBuilder(6200) - 不确定长度但数据量大(如万级日志缓冲),宁可略高估(如设 8192),避免多次翻倍扩容(扩容公式:新容量 = 旧容量 × 2 + 2)
- 在
ThreadLocal<stringbuilder></stringbuilder>场景下,推荐固定容量(如 1024),每次复用前调用setLength(0)清空,比新建更轻量
链式 append 是高效写法的核心
高效不只靠换类,更靠写法细节:
- 坚持链式调用:
sb.append("id=").append(id).append(", name=").append(name)—— 支持多种类型参数,自动 toString(),无中间对象 - 别混用
+和append:sb.append("a" + "b")会让编译器先建临时 StringBuilder,再 toString,白费一次开销 - 绝对避免在循环里写
String s = ""; s += item;—— 每次迭代都新建 String 和 StringBuilder,时间复杂度接近 O(n²) - 拼完务必调用
toString()获取结果;非必要少用insert/replace/reverse,它们涉及字符移动,开销远高于append
StringBuilder 和 StringBuffer 到底选哪个
二者底层结构一致,区别只在并发支持:
- 绝大多数情况选 StringBuilder:方法内局部变量、工具类私有字段、ThreadLocal 缓冲区——单线程,无锁,性能最高
- 仅当多线程共享同一实例时才考虑 StringBuffer:比如老系统中全局静态的配置拼接器(但更推荐改造成局部构造或使用 ConcurrentMap 缓存)
-
严禁 static StringBuilder 全局共享:会导致乱序、丢字符,甚至
ArrayIndexOutOfBoundsException,这是典型并发 bug
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










