目录
[1. 概述对比](#1. 概述对比)
[2. String:不可变的字符串](#2. String:不可变的字符串)
[2.1 基本特性](#2.1 基本特性)
[2.2 使用示例](#2.2 使用示例)
[2.3 适用场景](#2.3 适用场景)
[3. StringBuffer:可变的线程安全字符串](#3. StringBuffer:可变的线程安全字符串)
[3.1 基本特性](#3.1 基本特性)
[3.2 使用示例](#3.2 使用示例)
[3.3 适用场景](#3.3 适用场景)
[4. StringBuilder:可变的非线程安全字符串](#4. StringBuilder:可变的非线程安全字符串)
[4.1 基本特性](#4.1 基本特性)
[4.2 使用示例](#4.2 使用示例)
[4.3 适用场景](#4.3 适用场景)
[5. 性能对比](#5. 性能对比)
[5.1 性能测试代码](#5.1 性能测试代码)
[5.2 测试结果](#5.2 测试结果)
[6. 内存使用对比](#6. 内存使用对比)
[6.1 String 的内存使用](#6.1 String 的内存使用)
[6.2 StringBuffer/StringBuilder 的内存使用](#6.2 StringBuffer/StringBuilder 的内存使用)
[7. 最佳实践](#7. 最佳实践)
[7.1 选择原则](#7.1 选择原则)
[7.2 代码示例](#7.2 代码示例)
[7.3 初始化容量优化](#7.3 初始化容量优化)
[8. 总结](#8. 总结)
在 Java 开发中,字符串处理是最常见的操作之一。Java 提供了三种主要的字符串类:String、StringBuffer 和 StringBuilder。理解它们之间的区别对于编写高效、正确的代码至关重要。
1. 概述对比
|----------|-------------|--------------|---------------|
| 特性 | String | StringBuffer | StringBuilder |
| 可变性 | 不可变 | 可变 | 可变 |
| 线程安全 | 是(天生线程安全) | 是(同步方法) | 否(非线程安全) |
| 性能 | 最低(频繁创建新对象) | 中等(有同步开销) | 最高(无同步开销) |
| 使用场景 | 字符串常量、少量操作 | 多线程环境下的字符串操作 | 单线程环境下的字符串操作 |
| 内存效率 | 低(频繁操作时) | 高 | 最高 |
| 版本引入 | Java 1.0 | Java 1.0 | Java 5 |
2. String:不可变的字符串
2.1 基本特性
String 是不可变类,一旦创建就不能修改。任何看似修改 String 的操作实际上都是创建了一个新的 String 对象。
java
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; // Java 8 及之前
private final byte[] value; // Java 9 及之后
// ...
}
2.2 使用示例
java
// 创建字符串
String str1 = "Hello"; // 字面量方式,放入字符串常量池
String str2 = new String("Hello"); // 创建新对象
// 字符串操作(都返回新对象)
String result = str1.concat(" World"); // 拼接
String upper = result.toUpperCase(); // 转大写
String sub = result.substring(6); // 子字符串
System.out.println(str1); // 输出: Hello(原字符串未改变)
System.out.println(result); // 输出: Hello World
2.3 适用场景
- 字符串常量定义
- 不需要频繁修改的字符串
- 作为 HashMap 的键(利用不可变性)
- 多线程环境下的字符串共享
3. StringBuffer:可变的线程安全字符串
3.1 基本特性
StringBuffer 是可变的字符序列,所有修改方法都使用 synchronized
关键字保证线程安全。
java
public final class StringBuffer extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
// 其他方法也都是同步的
}
3.2 使用示例
java
StringBuffer sb = new StringBuffer("Hello");
// 链式操作,直接修改原对象
sb.append(" ")
.append("World")
.append("!")
.insert(5, " Beautiful");
System.out.println(sb.toString()); // 输出: Hello Beautiful World!
// 线程安全示例
StringBuffer threadSafeBuffer = new StringBuffer();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
threadSafeBuffer.append(i).append(" ");
}
};
// 多个线程同时操作是安全的
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
3.3 适用场景
- 多线程环境下的字符串操作
- 需要线程安全的字符串构建
- 复杂的字符串拼接和修改
4. StringBuilder:可变的非线程安全字符串
4.1 基本特性
StringBuilder 与 StringBuffer API 几乎完全相同,但方法没有同步,因此性能更高。
java
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
// 方法没有 synchronized 关键字
}
4.2 使用示例
java
StringBuilder sb = new StringBuilder("Hello");
// 高效的链式操作
sb.append(" ")
.append("World")
.append("!")
.insert(5, " Amazing");
System.out.println(sb.toString()); // 输出: Hello Amazing World!
// 单线程环境下性能最佳
long startTime = System.currentTimeMillis();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100000; i++) {
builder.append(i);
}
long endTime = System.currentTimeMillis();
System.out.println("StringBuilder 耗时: " + (endTime - startTime) + "ms");
4.3 适用场景
- 单线程环境下的字符串操作
- 性能要求高的字符串处理
- 大量的字符串拼接和修改
5. 性能对比
5.1 性能测试代码
java
public class StringPerformanceTest {
private static final int ITERATIONS = 100000;
public static void testString() {
long start = System.currentTimeMillis();
String str = "";
for (int i = 0; i < ITERATIONS; i++) {
str += i; // 每次循环创建新对象
}
long end = System.currentTimeMillis();
System.out.println("String 耗时: " + (end - start) + "ms");
}
public static void testStringBuffer() {
long start = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < ITERATIONS; i++) {
sb.append(i);
}
long end = System.currentTimeMillis();
System.out.println("StringBuffer 耗时: " + (end - start) + "ms");
}
public static void testStringBuilder() {
long start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ITERATIONS; i++) {
sb.append(i);
}
long end = System.currentTimeMillis();
System.out.println("StringBuilder 耗时: " + (end - start) + "ms");
}
public static void main(String[] args) {
testString();
testStringBuffer();
testStringBuilder();
}
}
5.2 测试结果
java
String 耗时: 4235ms
StringBuffer 耗时: 8ms
StringBuilder 耗时: 5ms
6. 内存使用对比
6.1 String 的内存使用
java
String result = "";
for (int i = 0; i < 10; i++) {
result += i; // 创建11个String对象
}
// 产生大量垃圾对象,增加GC压力
6.2 StringBuffer/StringBuilder 的内存使用
java
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i); // 在同一个缓冲区中操作
}
// 只在需要时扩容,内存使用高效
7. 最佳实践
7.1 选择原则
1.使用 String:
- 字符串常量
- 不需要修改的字符串
- 多线程共享的字符串
2.使用 StringBuffer:
- 多线程环境下的字符串操作
- 需要线程安全的字符串构建
3.使用 StringBuilder:
- 单线程环境下的字符串操作
- 性能要求高的场景
- 方法内部的字符串处理
7.2 代码示例
java
public class StringBestPractices {
// 常量使用 String
public static final String DATABASE_URL = "jdbc:mysql://localhost:3306/mydb";
// 方法参数使用 String(不可变,安全)
public void processMessage(String message) {
// 处理消息
}
// 单线程字符串构建使用 StringBuilder
public String buildQuery(List<String> conditions) {
StringBuilder query = new StringBuilder("SELECT * FROM users WHERE 1=1");
for (String condition : conditions) {
query.append(" AND ").append(condition);
}
return query.toString();
}
// 多线程环境使用 StringBuffer
public class ThreadSafeLogger {
private StringBuffer logBuffer = new StringBuffer();
public synchronized void log(String message) {
logBuffer.append(new Date())
.append(": ")
.append(message)
.append("\n");
}
public String getLog() {
return logBuffer.toString();
}
}
}
7.3 初始化容量优化
java
// 如果知道大致长度,可以预先设置容量
StringBuilder sb = new StringBuilder(1000); // 预分配容量
for (int i = 0; i < 1000; i++) {
sb.append("item").append(i).append(",");
}
// 避免多次扩容,提高性能
8. 总结
|----------|----------|--------------|---------------|
| 方面 | String | StringBuffer | StringBuilder |
| 核心特点 | 不可变 | 可变、线程安全 | 可变、非线程安全 |
| 性能排序 | 最慢 | 中等 | 最快 |
| 线程安全 | 是 | 是 | 否 |
| 内存效率 | 低(频繁操作时) | 高 | 最高 |
| 使用场景 | 常量、少量操作 | 多线程字符串操作 | 单线程字符串操作 |
黄金法则:
- 如果字符串不需要改变:使用 String
- 如果在单线程中需要改变字符串:使用 StringBuilder
- 如果在多线程中需要改变字符串:使用 StringBuffer
希望本篇文章对你有帮助。