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

相关推荐
寻星探路3 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
想用offer打牌5 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
曹牧6 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX6 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法7 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7257 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎7 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄7 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea