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

相关推荐
陈随易2 小时前
在 VSCode 里,把项目一键部署到服务器
前端·后端·程序员
鱼樱前端2 小时前
我用 Claude Code 后,编码效率翻 3 倍。但更值钱的是别的。
前端·后端·ai编程
犀利豆3 小时前
Claude code tools 研究系列-开篇(AskUserQuestion)
后端
头发还在的女程序员3 小时前
医院陪诊管理系统怎么选择?——2026 年选型避坑与架构参考
java·开发语言·陪诊系统·陪诊app·医院陪诊陪护
CodeStats3 小时前
【Spring事务】Spring事务注解 @Transactional 完整体系:从 MySQL 隔离级别到 MyBatis 原理详解
java·spring·mybatis·事务·transactional
我命由我123454 小时前
Android 开发问题:为 PDFView 设置一个带有黑色边框的背景 drawable,但边框没有生效
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
颜酱6 小时前
06 | 把 meta_config 同步进 MySQL(生成阶段)
前端·人工智能·后端
都叫我大帅哥6 小时前
从Python到Java:为什么企业级Agent最终会选择Java?
java·ai编程
wanderist.6 小时前
Lambda表达式在算法竞赛中的应用
java·开发语言·算法
IT_陈寒7 小时前
SpringBoot自动配置坑了我一周,原来问题这么蠢!
前端·人工智能·后端