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

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

相关推荐
计算机学长felix20 小时前
基于SpringBoot的“面向校园的助力跑腿系统”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·后端
fat house cat_20 小时前
【netty】基于主从Reactor多线程模型|如何解决粘包拆包问题|零拷贝
java·服务器·网络·netty
青云交21 小时前
Java 大视界 -- Java 大数据在智能教育学习社区互动模式创新与用户活跃度提升中的应用(426)
java·大数据·学习·flink 实时计算·智能教育社区·互动模式创新·用户活跃度
神奇的海马体21 小时前
Tomcat隐藏版本号
java·tomcat
拜见老天師21 小时前
使用mybatis-plus,实现将排序时,字段值为NULL的数据排在最后
java·mybatis
紫荆鱼21 小时前
设计模式-迭代器模式(Iterator)
c++·后端·设计模式·迭代器模式
应茶茶21 小时前
C++11 核心新特性:从语法重构到工程化实践
java·开发语言·c++
RainSky_21 小时前
LNMP 一键安装包部署 Django 项目
后端·django·1024程序员节
追逐时光者1 天前
一个开源免费、轻量级的 Avalonia UI 控件库
后端·.net
Reggie_L1 天前
RabbitMQ -- 高级特性
java·rabbitmq·java-rabbitmq