Java 字符串拼接用 +、StringBuilder 还是 StringBuffer?一篇给你终极答案

在 Java 开发中,字符串拼接几乎无处不在。

但是很多人依然搞不清:

  • "a" + "b"StringBuilder.append() 性能差多少?
  • StringBufferStringBuilder 到底该选哪个?
  • 为什么有时 + 也能很快?

本文将从原理、性能、线程安全、最佳实践四个方面,帮你彻底搞懂这个问题。


1. 三者的基本认识

1.1 + 运算符

  • 是 Java 的语法糖
  • 编译期javac 会将非循环内的字符串常量拼接优化为一个常量。
  • 运行期+ 会被编译器转成使用 StringBuilder (早期版本是 StringBuffer,JDK5 后改成 StringBuilder)。
  • 本质上 + 并不是直接的"字符串相加",而是 创建 StringBuilder → append → toString

1.2 StringBuilder

  • 可变 的字符序列(String 是不可变的)。
  • 非线程安全,但速度快。
  • 适用于单线程、多次拼接的场景。
  • API:append()insert()delete() 等。

1.3 StringBuffer

  • StringBuilder 类似,但线程安全 (方法上有 synchronized)。
  • 在多线程并发修改同一字符串时安全,但性能比 StringBuilder 略低。
  • 单线程下不推荐使用。

2. 工作原理 & 编译器优化

2.1 常量折叠(编译期优化)

java 复制代码
String s = "a" + "b" + "c";
System.out.println(s); // abc

编译后字节码中会直接变成:

java 复制代码
String s = "abc";

没有运行期开销


2.2 循环内拼接

java 复制代码
String s = "";
for (int i = 0; i < 1000; i++) {
    s = s + i;
}

编译器会转成:

java 复制代码
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(s).append(i);
    s = sb.toString();
}
  • 每次 toString() 都会创建新 String 对象 → 大量内存浪费,性能差

2.3 手动 StringBuilder

java 复制代码
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String s = sb.toString(); // 一次性生成
  • 只有一次 toString() 调用,性能更优。

3. 性能对比

一个简单的 10000 次拼接测试(单线程):

方法 时间 (ms) 特点
+ (循环内) 400+ 大量中间对象
StringBuilder 3~5 性能最佳
StringBuffer 8~10 线程安全,稍慢

(测试环境:JDK 17,本地单线程,结果随机器差异)


4. 线程安全问题

场景 选择
单线程 StringBuilder(性能优先)
多线程,同一实例被多个线程修改 StringBuffer(保证同步)
多线程,但每个线程有自己实例 StringBuilder(无共享状态)

5. 最佳实践建议

  1. 能用常量直接拼接就用常量(编译期优化,无运行时开销)。

  2. 循环中多次拼接 → 直接用 StringBuilder

  3. 多线程共享可变字符串 → 用 StringBuffer

  4. 拼接规模已知 → 初始化 StringBuilder 容量:

    java 复制代码
    StringBuilder sb = new StringBuilder(1024);

    避免频繁扩容。


6. 小结对比表

特性 + StringBuilder StringBuffer
语法简洁
性能(循环内) 中等
线程安全
适用场景 少量拼接 单线程多拼接 多线程共享

一句话记忆

少量拼接用 +,单线程多次拼接用 StringBuilder,多线程共享用 StringBuffer

相关推荐
20岁30年经验的码农21 分钟前
Spring Cloud Gateway 网关技术文档
java
likuolei1 小时前
XML DOM 节点类型
xml·java·服务器
w***74403 小时前
SpringBoot项目如何导入外部jar包:详细指南
spring boot·后端·jar
ZHE|张恒3 小时前
Spring Bean 生命周期
java·spring
tsumikistep4 小时前
【前后端】接口文档与导入
前端·后端·python·硬件架构
q***38515 小时前
SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
java·spring cloud·gateway
小白学大数据5 小时前
Python爬虫伪装策略:如何模拟浏览器正常访问JSP站点
java·开发语言·爬虫·python
码事漫谈5 小时前
为什么C语言拒绝函数重载?非要重载怎么做?
后端
码事漫谈5 小时前
浅谈C++与C语言二进制文件差异(从一次链接错误说起)
后端
程序员西西6 小时前
SpringBoot接口安全:APIKey保护指南
java·spring boot·计算机·程序员·编程·编程开发