StringBuilder.append()是唯一推荐的拼接方法,应避免字符串+操作;需预估容量、处理null、线程不安全但局部使用即可;简单分隔用String.join()更优。

StringBuilder.append() 是唯一该用的方法
直接调用 append(),别写 sb.toString() + "xxx" 或 sb + "xxx" —— 这会瞬间创建新 String 对象,让 StringBuilder 失效。它内部是可变字符数组,append() 就是在原数组上追加,不分配新对象。
常见错误现象:for 循环里反复拼接却混用 +,结果 GC 压力飙升,性能比直接用 + 还差。
- 所有拼接操作必须链式调用
append():比如sb.append("id:").append(id).append(", name:").append(name) - 传入
null会被转成字符串"null",如果业务不允许,得提前判空或用Objects.toString(x, "") - 避免在循环内反复调用
toString()—— 每次都复制整个底层数组,O(n) 开销
初始化容量能省掉 70% 的数组扩容
默认构造的 StringBuilder 初始容量是 16,一旦超了就触发扩容(通常是 2×+2),涉及数组复制。如果你知道最终长度大概多少,直接指定容量更稳。
使用场景:拼接日志、SQL 拼装、JSON 片段等长度可预估的批量操作。
立即学习“Java免费学习笔记(深入)”;
- 估算总长:把所有静态文本长度 + 所有变量可能的最大长度加起来(比如
int最多 11 位,UUID固定 36 位) - 宁大勿小:多留 10–20 字符余量,比频繁扩容划算
- 别用
new StringBuilder().ensureCapacity(n)—— 多一次方法调用,且ensureCapacity()不缩容,只扩
String.join() 比 StringBuilder 更适合简单分隔拼接
如果只是把一个 List<String> 用逗号或制表符连起来,别手写循环 + append()。JDK 8+ 的 String.join() 内部就是优化过的 StringBuilder,但封装了边界逻辑,还自动跳过 null 元素(抛 NullPointerException,而非拼出 "null")。
性能差异不大,但可读性和安全性更高;反过来,要插动态前缀/后缀、条件拼接、嵌套结构时,还是得回 StringBuilder。
- 用法示例:
String.join(",", list)或String.join("\t", arr) - 注意:
String.join()第一个参数是CharSequence,支持""、"\n",但不能为null,否则抛NullPointerException - 不适用于需要格式化、条件跳过、或中间插入非字符串内容(如数字计算结果)的场景
线程安全不是你该操心的事
StringBuilder 是线程不安全的,但绝大多数场景下——比如 Web 请求处理、批处理单线程任务、工具类局部变量——根本不需要同步。真要跨线程共享拼接结果,应该用不可变对象(如拼完再发布),而不是给 StringBuilder 加锁。
容易踩的坑:看到 “Builder” 就联想 “线程安全”,或者为了“保险”在方法里 synchronized(sb),这反而导致串行瓶颈,吞掉所有性能收益。
- 99% 的情况,
StringBuilder应声明为方法内局部变量,用完即弃 - 若需复用(如在对象字段中),确保该对象本身是线程私有的(例如 Spring 的
@Scope("prototype")Bean) - 别为了“看起来安全”而用
StringBuffer—— 它每个方法都同步,实测比StringBuilder慢 2–3 倍
null 处理逻辑 —— 这俩不显眼,但一上线就容易在高并发或异常数据下暴露。











