StringBuilder初始化容量应预估最终长度(如40000)而非依赖默认16,避免频繁扩容;单任务中复用同一实例并用setLength(0)清空;多线程需改用StringBuffer;append(null)在JDK8+抛NPE,应先判空或用Objects.toString。

StringBuilder初始化容量设多少才不浪费
Java里StringBuilder默认构造函数用的是16字符初始容量。但实际拼接中,如果最终字符串远超这个长度(比如拼1000个JSON字段),就会反复扩容:每次扩容是“当前容量×2+2”,触发数组复制,性能悄悄掉坑里。
常见错误现象:StringBuilder在循环内反复append大量数据,但没预估长度,GC日志里看到频繁的char[]分配和拷贝。
实操建议:
- 估算最终字符串长度(比如每条记录平均80字节 × 500条 ≈ 40,000),直接传入
new StringBuilder(40000) - 如果长度完全不可知,宁可略高估(如+20%),也别依赖默认值
- 注意:传入负数会抛
IllegalArgumentException,0是合法的,但后续第一次append仍要扩容
循环内反复new StringBuilder还是复用一个
很多人以为“每次循环新建更安全”,结果在高频日志拼接或模板渲染场景下,对象创建+GC压力陡增。
使用场景:批量生成SQL、HTTP响应体、CSV行拼接等需多次独立拼接的场合。
实操建议:
- 单次任务中多个拼接步骤(比如先拼header,再拼body,最后加footer),复用同一个
StringBuilder,用setLength(0)清空比new快得多 - 多线程环境下不能复用,
StringBuilder不是线程安全的;该用StringBuffer就用,别硬套StringBuilder -
setLength(0)比delete(0, length())更快,它不检查边界也不移动内容,只是重置长度指针
append(null)到底会不会NPE
这个问题常出现在处理可能为null的DTO字段时。答案是:会,但只在JDK 8及以后版本明确抛NullPointerException;JDK 7及以前是拼出字符串"null"。
参数差异:
-
append(String):传null→ NPE(JDK 8+) -
append(Object):传null→ 拼"null"(因为调用了String.valueOf(obj)) -
append(char[])传null→ NPE(所有JDK版本一致)
容易踩的坑:
- 用
append(obj.toString())前没判空,直接崩 - 想兼容旧逻辑而误用
append((Object) str),结果把"null"写进输出里,排查困难 - 实际应统一用
Objects.toString(str, "")再append
String.join vs StringBuilder谁更适合多字段拼接
当拼接固定数量、已存在的字符串(比如String.join(",", a, b, c)),String.join语义清晰且内部也用StringBuilder,性能差距微乎其微。
但真实业务里更多是动态拼接:字段数不定、中间要加条件判断、某些字段可能跳过。
性能影响:
-
String.join要求所有元素非null(否则NPE),且必须提前准备好集合或数组 -
StringBuilder支持流式控制:可以if (x != null) sb.append(x),避免冗余分隔符 - 连续调用
join(比如循环里反复String.join(",", list))会反复创建StringBuilder和数组,不如外层复用一个
实操建议:
- 纯静态、无逻辑、无null风险的拼接,用
String.join更干净 - 只要涉及条件分支、null处理、或拼接过程有状态(比如“除了第一个都加前缀”),老老实实用
StringBuilder,别为了语法糖牺牲可控性
字符串拼接看着简单,但StringBuilder的容量估算、复用时机、null处理路径,三处任一选错,性能就从O(n)退化成O(n²),而且问题往往压测才暴露。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











