String、StringBuffer、StringBuilder是 Java 中用于处理字符串的三个核心类,它们的区别主要体现在可变性、线程安全性和性能上。以下是它们的对比及适用场景分析:
1.核心区别
特性 | String | StringBuffer | StringBuilder |
可变性 | 不可变 | 可变 | 可变 |
线程安全 | 线程安全(天然不可变) | 线程安全(方法用 synchronize修饰) | 非线程安全 |
性能 | 低(频繁修改会产生大量新对象) | 中(线程安全带来额外开销) | 高(无同步开销) |
适用场景 | 常量或少量修改 | 多线程环境下的字符串操作 | 单线程环境下的字符串操作 |
2.详细分析
(1)String:不可变的字符串
l 特点:每次修改(如拼接、替换)都会生成新对象,原对象不变。
l 优点:天然线程安全(不可变对象);适合缓存(如哈希值只需计算一次)。
l 缺点:频繁修改时性能差(内存和 GC 压力大)。
l 示例:
String str = "Hello";
str += " World"; // 生成新对象,原对象仍在内存中
(2)StringBuffer:线程安全的可变字符串
l 特点:内部通过 synchronized 保证线程安全,适合多线程环境。
l 优点:线程安全,适合共享资源的修改。
l 缺点:同步锁导致性能略低于 StringBuilder。
l 示例:
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World"); // 直接修改原对象,线程安全
(3)StringBuilder:非线程安全的可变字符串
l 特点:去掉了 synchronized 修饰,性能最高。
l 优点:单线程下性能最优。
l 缺点:多线程环境下需自行保证安全。
l 示例:
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 直接修改原对象,无同步开销
3.应用场景
(1)使用 String 的情况
字符串内容固定(如常量、配置键);无需频繁修改的场景(如 SQL 语句模板);需要线程安全的只读操作。
(2)使用 StringBuffer 的情况
多线程环境下频繁修改字符串(如日志缓冲、并发处理文本);需要保证线程安全的动态字符串操作。
(3)使用 StringBuilder 的情况
单线程环境下频繁修改字符串(如循环拼接 SQL、JSON)。性能敏感的场景(如大数据量处理)。
4.性能对比
l 单线程环境:StringBuilder > StringBuffer > String。
l 多线程环境:StringBuffer 是唯一选择(或通过外部同步机制使用 StringBuilder)。
5.最佳实践
l 避免在循环中使用 String 拼接:
// 错误示例(性能差)
String result = "";
for (int i = 0; i < 1000; i++) {
result += i;
}
// 正确示例(使用 StringBuilder)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();
l 多线程共享时选择 StringBuffer:
StringBuffer buffer = new StringBuffer();
Runnable task = () -> buffer.append("data"); // 多线程安全
6.总结
l 优先选 String:内容固定或少量修改时。
l 优先选 StringBuilder:单线程频繁修改时。
l 必须用 StringBuffer:多线程共享修改时。