string不可变、线程安全但拼接低效,适用于常量、map键等;stringbuilder单线程可变、高性能,适合日常大量拼接;stringbuffer多线程可变、方法同步,适用于真正共享实例的并发场景。

选对字符串类型,不是靠猜,而是看场景。String、StringBuilder、StringBuffer 本质解决的是不同维度的问题:不变性、可变性、并发安全。用错一个,轻则性能掉一截,重则多线程下数据错乱。
什么时候必须用 String
String 的核心价值不是“拼接”,而是“不可变”带来的安全性与复用性。
- 作为常量或配置项使用,比如
"api.timeout"、"UTF-8"—— 不可变保证了全局一致性 - 用作 Map 的 key(如
Map<string object></string>)—— 因为实现了equals()和hashCode(),且内容稳定 - 需要字符串常量池优化的场景,例如大量重复短字符串(如状态码
"SUCCESS"、"ERROR")—— JVM 自动复用,节省内存 - 涉及敏感信息(如密码临时封装)—— 不可变意味着不会被意外篡改,也便于及时丢弃(虽然仍需注意清空 char[])
单线程大量拼接?优先选 StringBuilder
日常开发中,90% 以上的字符串构建都在单线程里完成,比如生成日志、组装 SQL、构造 JSON 片段。这时 StringBuilder 是默认最优解。
- 底层基于可变 char[]/byte[],append、insert 等操作直接修改原数组,不创建中间对象
- 没有 synchronized 开销,比 StringBuffer 快约 10%–15%(实测百万次拼接,差距明显)
- JDK 编译器对
String s = a + b + c的优化,底层就是自动转成 StringBuilder.append(),说明它已是事实标准 - 注意初始化容量:如果预估最终长度(如拼接 1000 条记录,每条约 50 字符),建议用
new StringBuilder(50000),避免多次扩容复制
多线程共享拼接?才考虑 StringBuffer
StringBuffer 不是“过时技术”,而是在特定并发场景下的合理选择——前提是:多个线程真的会共用同一个实例并同时调用 append 等方法。
- 所有 public 修改方法(
append、insert、delete)都加了synchronized,保障方法级原子性 - 适合被注入为成员变量并在多个线程间传递使用的工具类(如某些老系统中的全局日志缓冲器)
- 但要注意:它只保证单个方法线程安全,不保证复合操作(如
if (sb.length() )的原子性,仍需外部同步 - 现代开发更推荐用局部 StringBuilder + 显式传参,或用 ThreadLocal 封装,避免共享状态 —— 这比依赖 StringBuffer 更清晰、更可控
转换与边界提醒
三者之间不能直接强制转型,但有明确的协作路径:
- String → StringBuilder:用
new StringBuilder(str)或StringBuilder.append(str) - StringBuilder → String:必须调用
toString()—— 返回新 String,底层复制字符数组,不是引用共享 - StringBuffer 和 StringBuilder API 完全一致,互换只需改类名,但别在无并发需求时硬切 StringBuffer
- 别把 StringBuilder 当“万能缓存”长期持有;它不是线程安全的,也不适合跨请求复用(如放在 Spring Bean 中作为字段)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











