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

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

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

一、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:多线程下的"安全卫士"

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

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能保证顺序正确。

但是!

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

四、总结

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

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

相关推荐
香蕉大香蕉(06敬畏市场)几秒前
MySQL 单点详解(01)
java·数据库·mysql·面试·博客·实习
小小张说故事14 分钟前
Python 的 str 为什么设计成不可变?拆开字符串驻留、字符串池,以及 += 拼接到底慢在哪
后端·python
LaughingZhu16 分钟前
Product Hunt 热榜 2026-10-30:Empacer、Scape、Floot in ChatGPT
java·前端·数据库·人工智能·chatgpt·notion
AI架构师之家24 分钟前
我把 Hermes 这匹"马"养了两周,它干了一件让我有点发毛的事
后端
dpharness31 分钟前
块协议用了两周,我把九个坑按顺序记下来了
后端
niucloud-admin34 分钟前
NIUCLOUD PHP SAAS上门家政使用文档:服务保障
java·开发语言·php
加宝的起点雷达42 分钟前
跑了两周的信号日报,我把降级链改了四次
人工智能·后端
IT枫斗者枫哥1 小时前
CompletableFuture失败后返回空列表:异常没了,业务含义也变了
java·后端
Gopher_HBo1 小时前
opentelemetrySDK源码解析
后端
知识搬运临时工1 小时前
一个模板把 AEM 拖进 Full GC 死亡螺旋:300% CPU、7 GB 堆、310 万行堆栈
java·aws