String、StringBuffer和StringBuilder,别再用错了!

写 Java 的时,你有没有遇到过这种情况:拼接个字符串,发现程序变慢了?或者多线程环境下,拼出来的字符串乱了?其实,很多时候问题就出在于你用了不该用的"字符串"。

Java里有三个常用的字符串相关类:StringStringBufferStringBuilder。它们看着像一家人,但如果用错了地方,可能会出现性能差或者其它的问题。

一、String:用在"不变"的场景

String是不可变的。一旦你创建了一个字符串,它就定下来了,改不了。如果你改了它,其实是新建了一个字符串。

比如:

java 复制代码
String str = "Hello";
str = str + " World";

你以为是改了str?其实是在内存里新建了一个"Hello World",原来的"Hello"被丢掉了。

使用场景:

  • 字符串内容固定不变
  • 作为配置项、常量、Map的key
  • 简单拼接,次数少(1~2 次)

案例:

你从配置文件读了个数据库地址:

java 复制代码
String dbUrl = "jdbc:mysql://localhost:3306/mydb";

这个地址不会变,就用String,简单直接。

注意:

别拿 String去搞循环拼接!比如:

java 复制代码
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i; // 每次都新建对象,内存爆炸!
}

这种写法在小数据量时看不出问题,数据一大,程序直接卡死。

二、StringBuilder:单线程下,拼接字符串的"快枪手"

如果你要在一个线程里 拼接大量字符串StringBuilder是首选。

它可变,而且速度快,内存消耗小。

使用场景:

  • 单线程下大量字符串拼接
  • 构造 JSON、SQL 语句
  • 日志信息组装

案例 1:拼接 SQL

java 复制代码
StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1");
if (age > 0) {
    sql.append(" AND age > ").append(age);
}
if (name != null) {
    sql.append(" AND name LIKE '%").append(name).append("%'");
}

这种动态 SQL,用StringBuilder拼,又快又安全。

案例 2:生成日志消息

java 复制代码
StringBuilder logMsg = new StringBuilder();
logMsg.append("用户 ").append(userId)
      .append(" 在 ").append(new Date())
      .append(" 执行了操作:").append(action);
System.out.println(logMsg.toString());

拼接几个字段,清晰又高效。 只要是一个人干活(单线程),拼字符串多,就用StringBuilder

三、StringBuffer:多线程下的"安全卫士"

StringBufferStringBuilder功能几乎一样,都能拼接字符串。区别在哪?线程安全。

StringBuffer的每个方法都加了锁(synchronized),多个线程同时操作也不会乱。

使用场景:

  • 多线程环境下拼接字符串
  • 全局共享的字符串缓冲区
  • 对线程安全有要求的场景

案例:

假设你有个计数器,多个线程往一个日志缓冲区里写信息:

java 复制代码
// 全局共享
StringBuffer sharedLog = new StringBuffer();

// 线程1
new Thread(() -> {
    sharedLog.append("Thread-1: 开始处理\n");
    // ...处理逻辑
    sharedLog.append("Thread-1: 处理完成\n");
}).start();

// 线程2
new Thread(() -> {
    sharedLog.append("Thread-2: 开始处理\n");
    // ...处理逻辑
    sharedLog.append("Thread-2: 处理完成\n");
}).start();

这时候用StringBuilder就可能出问题------两个线程同时写,内容可能错乱、丢失。而StringBuffer能保证顺序正确。

但是!

加锁是有代价的。StringBufferStringBuilder慢一点。所以,如果不是多线程,别用它

四、总结

场景 用哪个? 为什么?
字符串不变,简单使用 String 简单直观,适合常量
单线程,大量拼接 StringBuilder 快,不加锁,效率高
多线程,共享拼接 StringBuffer 安全,防止数据错乱
循环拼接(不管多少线程) 别用 String 性能极差,容易 OOM
  • 不变用 String
  • 单线程拼接用 StringBuilder
  • 多线程拼接用 StringBuffer

所以,别小看这几个类的选择。用对了,程序真的可以很稳;

相关推荐
IT_Octopus2 小时前
IntelliJ 本地日志路径自定义:`-DLOG_PATH=./logs` 为什么总“不听话“
java·log4j·intellij-idea
码事漫谈2 小时前
DeepSeek 这波操作很凶
后端
长征coder2 小时前
【无标题】
java·性能优化
新时代牛马3 小时前
PCI与PCIe 硬件原理、配置空间/BAR 与 Linux 驱动完整篇:从 LTSSM、TLP 到 ECAM 与probe
java·linux·服务器
Bs_MoneyMagnet3 小时前
基于springboot+vue的医疗健康便民服务平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
sunshine22 girl4 小时前
Java学习一 环境配置2 Idea的入门使用和maven配置,项目启动脚本配置
java·maven
有点。5 小时前
*C++哈夫曼树与哈夫曼编码
java·c++·servlet
子兮曰5 小时前
Bun v1.4.1 深度解析:从 Zig 到 Rust,一场 11 天、64 个 AI 代理的语言迁徙
前端·后端·bun
CRMEB系统商城5 小时前
CRMEB标准版系统(Java)v3.1正式发布
java·spring·微信小程序·php·教育电商
写后端的胖头鱼6 小时前
【高频面试题】Java 基础类型 + 包装类 + String 互相转换
java·开发语言