string适用于不可变场景,stringbuilder用于单线程大量拼接,stringbuffer仅在多线程真共享时使用;选型依据是可变性、线程环境与实例共享性。

日常开发中,String、StringBuilder 和 StringBuffer 的选型不是凭感觉,而是看三个硬指标:是否需要修改字符串、是否在单线程环境、是否多个线程共享同一个实例。
拼接少、不修改?直接用 String
String 适合做常量、配置项、Map 的 key、HTTP 请求路径这类“写完就不管”的场景。它不可变,天然线程安全,还能享受字符串常量池优化。比如:
String url = "https://api.example.com/v1/users/" + userId;
这种简单拼接,JDK 编译器会自动优化成 StringBuilder.append(),不用手动改;但若在循环里反复写 s = s + "x",就会每轮都新建对象,触发频繁 GC——这时候就得换。
单线程大量拼接?首选 StringBuilder
90% 以上的业务逻辑(如日志组装、SQL 拼接、JSON 构造)都在单线程中完成,StringBuilder 是默认答案。它没有 synchronized 开销,实测比 StringBuffer 快 10%–15%。关键细节有:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 初始化容量很重要:预估最终长度(例如拼 200 条日志,每条平均 80 字符),用 new StringBuilder(16000),避免多次扩容复制数组
- 方法链式调用很自然:sb.append("id=").append(id).append("&name=").append(name)
- 局部变量使用最安全:定义在方法内,用完即弃,不跨线程、不共享
多线程真共享?才考虑 StringBuffer
StringBuffer 不是过时技术,而是为一种特定并发模式设计的:多个线程确实共用同一个实例,并同时调用 append、insert 等操作。比如老系统里作为全局日志缓冲器被注入到多个服务类中。但它只保证单个方法原子性,像 if (sb.length() > 0) sb.delete(0, 1) 这种复合操作仍需额外加锁。现代更推荐两种替代方式:
- 把 StringBuilder 放在方法内部,通过参数显式传递,彻底避免共享
- 用 ThreadLocal 封装 StringBuilder,每个线程独享一份,兼顾性能与隔离性
别踩这些常见坑
误用会带来性能或并发问题:
- 在 for 循环里用 String += "x" —— 产生大量临时对象,GC 压力陡增
- 为图省事把 StringBuilder 设为类成员变量,在 Spring Bean 中被多线程复用 —— 非线程安全,结果错乱
- 以为 StringBuffer “更稳妥”就全项目统一用它 —— 白白承担同步开销,拖慢单线程路径
- 忽略初始容量,让 StringBuilder 在大文本拼接中反复扩容(16 → 34 → 70 → 142…),浪费 CPU 和内存
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










