为什么 StringBuilder 这么快?带你看懂底层实现

原文来自于:zha-ge.cn/java/30

为什么 StringBuilder 这么快?带你看懂底层实现

一个普通工作日的"性能危机"

那天下午,我正在优化一个数据处理模块。代码跑得慢得要命,CPU 使用率飙到 90%,领导催得紧。打开性能分析工具一看,竟然发现罪魁祸首是一个看似无害的字符串拼接循环:

java 复制代码
String result = "";
for (int i = 0; i < 10000; i++) {
    result += "item_" + i + ",";
}

这段代码要处理一万条数据,结果跑了将近 30 秒!我当时就懵了,不就是个字符串拼接吗,怎么会这么慢?

探索:String 的"黑暗秘密"

好奇心驱使我深入挖掘。原来,Java 中的 String 是不可变对象 ,每次 += 操作实际上都会:

  1. 创建一个新的 String 对象
  2. 把原字符串内容复制过去
  3. 把新内容追加上
  4. 丢弃旧对象

想象一下,一万次循环就是一万次"搬家"!每次都要把所有家当重新打包,能不累死吗?

转折:StringBuilder 的"魔法"登场

同事提醒我试试 StringBuilder。我半信半疑地改了代码:

java 复制代码
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append("item_").append(i).append(",");
}
String result = sb.toString();

结果让我大跌眼镜------从 30 秒变成了 0.05 秒!简直像是给程序装了火箭发动机。

解密:StringBuilder 的底层"黑科技"

我迫不及待地翻看了 StringBuilder 的源码,发现了它的秘密武器:

java 复制代码
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

// AbstractStringBuilder 中的核心逻辑
void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    if (newCapacity < minimumCapacity)
        newCapacity = minimumCapacity;
    value = Arrays.copyOf(value, newCapacity);
}

原来 StringBuilder 内部维护了一个可变的字符数组!它的聪明之处在于:

特性 StringBuilder String
存储方式 可变字符数组 不可变对象
容量策略 动态扩容(2倍+2) 每次新建
内存复制 仅扩容时 每次操作

踩坑瞬间

不过,我也遇到了一些意想不到的坑:

坑1:忘记设置初始容量 默认容量只有 16,频繁扩容还是会影响性能。对于大量数据,最好预估容量:

java 复制代码
StringBuilder sb = new StringBuilder(10000); // 预分配足够空间

坑2:多线程使用 StringBuilder 不是线程安全的!多线程环境下要用 StringBuffer,或者各线程独立使用。

坑3:过度优化 少量字符串拼接(比如 2-3 个),直接用 + 反而更简洁。编译器会自动优化成 StringBuilder。

经验启示

这次"性能危机"让我明白了几个道理:

  • 不要小看基础 API:String 和 StringBuilder 看似简单,底层机制却大有玄机
  • 性能问题要从根源找:不是代码写得不够复杂,而是用错了工具
  • 合适的数据结构是王道:可变 vs 不可变,一字之差,性能天壤之别

现在每当看到循环中的字符串拼接,我都会条件反射般想起那个惊心动魄的下午。StringBuilder 不只是一个工具类,更像是 Java 工程师的"性能救星"------它用一个简单的可变数组,解决了字符串操作的性能瓶颈。

记住这个故事,下次遇到类似场景,你就知道该选谁了!

相关推荐
wang09074 小时前
自己动手写一个spring之IOC_2
java·后端·spring
来杯@Java5 小时前
学生选课管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·maven·mybatis
不知名的老吴6 小时前
线程的生命周期之线程“插队“
java·开发语言·python
ANnianStriver6 小时前
PetLumina-02-后端开发与前后端联调
java·ai·sa-token
杨了个杨89826 小时前
Keepalived + Nginx + HAProxy 高可用架构部署实战案例
java·nginx·架构
马士兵教育9 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习
snow@li9 小时前
Java:理解 Gradle / 后端项目的管家 / 打包SpringBoot 应用 / 完成编译、下载依赖、运行测试、打包 JAR/WAR / 速查表
java
云烟成雨TD9 小时前
Spring AI 1.x 系列【57】动态工具发现:Tool Search Tool
java·人工智能·spring
zfoo-framework9 小时前
[修改代码使用]codex官方app中使用中转(不需要cc-switch) 1.config.toml 2.sk方式登录
java