结论:循环内反复拼接(如日志、sql、html生成)必须显式用stringbuilder;编译期可确定的少量拼接(1–2次)用“+”更简洁高效。

直接说结论:用 StringBuilder 拼接 3 次以上字符串时,性能明显优于 + 或 String.concat();但若只有 1–2 次拼接,编译器常自动优化为 StringBuilder,手动写反而多余。
什么时候必须显式用 StringBuilder?
典型场景是循环内反复拼接(比如日志组装、SQL 构建、HTML 片段生成),此时每次用 + 都会创建新 String 对象,触发频繁 GC。
- 循环次数 ≥ 5,且每次拼接内容长度 > 10 字符 → 强烈建议用
StringBuilder - 拼接逻辑跨多个方法调用(如递归、回调)→ 编译器无法优化,必须手动传入
StringBuilder实例 - 需要控制容量避免扩容(如已知最终长度约 2KB)→ 可用
new StringBuilder(2048)预分配
append() 的参数类型和隐式转换陷阱
StringBuilder.append() 重载多,但不是所有类型都“安全”。最常见问题是误传 null 或未处理的 Object:
- 传
null→ 实际追加字符串"null",不是空指针异常(容易漏掉) - 传自定义对象(没重写
toString())→ 拼出类似"com.example.User@1a2b3c",而非业务期望值 - 数字类型(
int/long)直接 append 是高效的,但double会触发装箱+字符串格式化,若需精度控制,改用String.format()后再 append
线程安全吗?能不能共享实例?
StringBuilder 是非线程安全的 —— 它没有同步开销,所以快;但也意味着不能在多个线程间共享同一个实例。
- 在单线程方法内局部创建(推荐):
StringBuilder sb = new StringBuilder(); - 在线程池任务中复用?可以,但必须确保该实例不被其他线程访问,例如通过
ThreadLocal管理 - 误用
static StringBuilder全局共享 → 出现乱序、丢失字符、甚至ArrayIndexOutOfBoundsException(扩容时内部数组被并发修改)
真正难的是预估初始容量和判断是否值得提前抽象——很多人在只拼 2 个字符串时硬套 StringBuilder,反而增加代码噪声。记住:优化要落在热路径上,而不是语法洁癖里。










