StringBuilder非线程安全因无synchronized修饰,多线程共享会出错;默认容量16,扩容耗性能,应预估大小;toString()开销小但类型需匹配;append不判空,索引操作前须校验长度。

Java面试中,StringBuilder看似简单,但常因理解偏差或忽略细节被问倒。避开这些坑,关键不是背答案,而是抓住底层逻辑和使用边界。
混淆线程安全性,误用场景
很多人只记住“StringBuilder非线程安全”,却说不清为什么。它不加锁、不同步,所有方法(如append、insert)直接操作内部char[] value和int count,没有synchronized修饰。多线程共用同一个StringBuilder实例时,可能出现字符覆盖、长度错乱甚至数组越界。
- 单线程拼接大量字符串 → 用StringBuilder,性能最优
- 多线程各自拼接 → 每个线程new自己的StringBuilder,无需改用StringBuffer
- 多线程共享拼接结果 → 必须加锁或换用StringBuffer,不能靠“我保证不会并发”来搪塞
忽略容量扩容机制,写出低效代码
StringBuilder默认初始容量是16。每次append超过当前容量时,会触发扩容:新容量 = 原容量 × 2 + 2(JDK 8+)。频繁扩容意味着反复创建更大数组、拷贝旧内容,拖慢性能。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 预估最终长度,显式指定容量:
new StringBuilder(1024) - 避免在循环内反复
toString()再新建StringBuilder——这等于放弃可变优势,退化成String拼接 - 注意
delete()或setLength(0)不会缩容,只是重置count;真正释放内存需重新new
误判String与StringBuilder的转换开销
有人以为sb.toString()很重,其实它只是新建一个String对象,内部value数组是复制(JDK 7u6以后),不共享。但反过来说,如果只是临时拼接后立即用作参数,没必要提前转String。
立即学习“Java免费学习笔记(深入)”;
- 日志拼接:
log.info("user={}, id={}", sb.toString())→ 直接传sb可能报错(log框架不识别),应确保类型匹配 - 作为Map键或需要不可变语义时,必须调用
toString()生成新String - 不要为“省一次toString”而把StringBuilder当全局缓存长期持有——易引发线程或状态污染
忽视空值与边界判断,引发NPE或越界
StringBuilder自身不校验null参数。比如sb.append(null)会写入字符串"null",而sb.insert(5, null)同样如此;但sb.delete(-1, 10)或sb.replace(100, 200, "x")会直接抛StringIndexOutOfBoundsException。
- 对外部传入的待拼接对象,先判空再append,或统一用
Objects.toString(obj, "") - 涉及索引操作(insert/delete/replace)前,检查
sb.length()是否满足范围要求 - 不要假设“我控制了输入就绝对安全”——面试官常故意给边界值测试鲁棒性

















