Appearance
13.3 StringBuffer 和 StringBuilder
StringBuffer 和 StringBuilder 的概念
StringBuffer 和 StringBuilder 是 Java 中用于处理可变字符串的类。它们与 String 类不同,String 是不可变的,而 StringBuffer 和 StringBuilder 是可变的,这意味着它们可以在不创建新对象的情况下修改字符串内容。
StringBuffer 和 StringBuilder 的区别
| 特性 | StringBuffer | StringBuilder |
|---|---|---|
| 线程安全性 | 线程安全,方法是同步的 | 非线程安全,方法不是同步的 |
| 性能 | 相对较低(因为同步) | 相对较高(因为不同步) |
| 适用场景 | 多线程环境 | 单线程环境 |
StringBuilder 的使用
构造方法
java
// 创建一个空的 StringBuilder
StringBuilder sb1 = new StringBuilder();
// 创建一个指定容量的 StringBuilder
StringBuilder sb2 = new StringBuilder(16);
// 创建一个包含指定字符串的 StringBuilder
StringBuilder sb3 = new StringBuilder("Hello");常用方法
append()
功能:向 StringBuilder 追加内容
语法:StringBuilder append(任意类型参数)
示例:
java
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("Java");
sb.append("!");
System.out.println(sb.toString()); // "Hello Java!"insert()
功能:在指定位置插入内容
语法:StringBuilder insert(int offset, 任意类型参数)
示例:
java
StringBuilder sb = new StringBuilder("Hello World!");
sb.insert(6, "Java ");
System.out.println(sb.toString()); // "Hello Java World!"delete()
功能:删除指定范围的内容
语法:StringBuilder delete(int start, int end)
示例:
java
StringBuilder sb = new StringBuilder("Hello Java World!");
sb.delete(6, 11); // 删除 "Java "
System.out.println(sb.toString()); // "Hello World!"deleteCharAt()
功能:删除指定位置的字符
语法:StringBuilder deleteCharAt(int index)
示例:
java
StringBuilder sb = new StringBuilder("Hello World!");
sb.deleteCharAt(5); // 删除空格
System.out.println(sb.toString()); // "HelloWorld!"replace()
功能:替换指定范围的内容
语法:StringBuilder replace(int start, int end, String str)
示例:
java
StringBuilder sb = new StringBuilder("Hello World!");
sb.replace(6, 11, "Java");
System.out.println(sb.toString()); // "Hello Java!"reverse()
功能:反转字符串
语法:StringBuilder reverse()
示例:
java
StringBuilder sb = new StringBuilder("Hello");
sb.reverse();
System.out.println(sb.toString()); // "olleH"substring()
功能:获取子串
语法:String substring(int start) 或 String substring(int start, int end)
示例:
java
StringBuilder sb = new StringBuilder("Hello Java!");
String sub1 = sb.substring(6); // "Java!"
String sub2 = sb.substring(0, 5); // "Hello"
System.out.println(sub1);
System.out.println(sub2);length()
功能:返回字符串长度
语法:int length()
示例:
java
StringBuilder sb = new StringBuilder("Hello");
int length = sb.length(); // 5
System.out.println("长度: " + length);capacity()
功能:返回当前容量
语法:int capacity()
示例:
java
StringBuilder sb1 = new StringBuilder();
System.out.println("默认容量: " + sb1.capacity()); // 16
StringBuilder sb2 = new StringBuilder("Hello");
System.out.println("容量: " + sb2.capacity()); // 16 + 5 = 21setLength()
功能:设置字符串长度
语法:void setLength(int newLength)
示例:
java
StringBuilder sb = new StringBuilder("Hello");
sb.setLength(3);
System.out.println(sb.toString()); // "Hel"StringBuffer 的使用
StringBuffer 的使用方法与 StringBuilder 基本相同,只是它的方法是同步的,线程安全。
示例:
java
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(" ");
sb.append("Java");
sb.append("!");
System.out.println(sb.toString()); // "Hello Java!"性能比较
String、StringBuilder 和 StringBuffer 的性能对比
java
public class StringPerformanceTest {
public static void main(String[] args) {
int iterations = 100000;
// 测试 String
long startTime = System.currentTimeMillis();
String str = "";
for (int i = 0; i < iterations; i++) {
str += i;
}
long endTime = System.currentTimeMillis();
System.out.println("String 耗时: " + (endTime - startTime) + " 毫秒");
// 测试 StringBuilder
startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append(i);
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder 耗时: " + (endTime - startTime) + " 毫秒");
// 测试 StringBuffer
startTime = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < iterations; i++) {
sbf.append(i);
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer 耗时: " + (endTime - startTime) + " 毫秒");
}
}运行结果(仅供参考):
String 耗时: 12345 毫秒
StringBuilder 耗时: 12 毫秒
StringBuffer 耗时: 15 毫秒应用场景
1. 大量字符串拼接
当需要进行大量字符串拼接操作时,使用 StringBuilder 或 StringBuffer 可以显著提高性能。
示例:
java
// 不推荐:使用 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();2. 字符串修改操作
当需要对字符串进行频繁的修改操作(如插入、删除、替换等)时,使用 StringBuilder 或 StringBuffer 更加高效。
示例:
java
StringBuilder sb = new StringBuilder("Hello World!");
// 插入操作
sb.insert(6, "Java ");
System.out.println(sb.toString()); // "Hello Java World!"
// 删除操作
sb.delete(6, 11);
System.out.println(sb.toString()); // "Hello World!"
// 替换操作
sb.replace(6, 11, "Java");
System.out.println(sb.toString()); // "Hello Java!"
// 反转操作
sb.reverse();
System.out.println(sb.toString()); // "!avaJ olleH"3. 线程安全场景
在多线程环境中,当多个线程需要修改同一个字符串时,使用 StringBuffer 可以保证线程安全。
示例:
java
public class ThreadSafeExample {
private static StringBuffer stringBuffer = new StringBuffer();
public static void main(String[] args) {
// 创建多个线程
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
final int threadId = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
stringBuffer.append("Thread " + threadId + ": " + j + "\n");
}
});
threads[i].start();
}
// 等待所有线程完成
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("字符串长度: " + stringBuffer.length());
}
}示例:StringBuilder 的应用
示例 1:构建复杂字符串
java
public class StringBuilderExample {
public static void main(String[] args) {
// 构建 HTML 字符串
StringBuilder html = new StringBuilder();
html.append("<html>\n");
html.append("<head>\n");
html.append("<title>Java StringBuilder Example</title>\n");
html.append("</head>\n");
html.append("<body>\n");
html.append("<h1>Hello, Java!</h1>\n");
html.append("<p>This is an example of using StringBuilder.</p>\n");
html.append("</body>\n");
html.append("</html>");
System.out.println(html.toString());
}
}示例 2:字符串反转
java
public class StringReverseExample {
public static void main(String[] args) {
String str = "Hello, Java!";
System.out.println("原始字符串: " + str);
System.out.println("反转后: " + reverseString(str));
}
public static String reverseString(String str) {
StringBuilder sb = new StringBuilder(str);
return sb.reverse().toString();
}
}示例 3:数字转字符串
java
public class NumberToStringExample {
public static void main(String[] args) {
int number = 12345;
String str = numberToString(number);
System.out.println("数字: " + number);
System.out.println("字符串: " + str);
}
public static String numberToString(int number) {
StringBuilder sb = new StringBuilder();
boolean isNegative = false;
if (number < 0) {
isNegative = true;
number = -number;
}
do {
int digit = number % 10;
sb.append((char) ('0' + digit));
number /= 10;
} while (number > 0);
if (isNegative) {
sb.append('-');
}
return sb.reverse().toString();
}
}常见问题
1. 线程安全问题
症状:在多线程环境中使用 StringBuilder 导致数据不一致
解决方案:在多线程环境中使用 StringBuffer,或使用同步机制保护 StringBuilder
示例:
java
// 多线程环境中使用 StringBuffer
StringBuffer sb = new StringBuffer();
// 或使用同步机制保护 StringBuilder
StringBuilder sb = new StringBuilder();
synchronized (sb) {
sb.append("Hello");
}2. 容量不足问题
症状:StringBuilder 或 StringBuffer 频繁扩容,影响性能
解决方案:在创建时指定合适的初始容量
示例:
java
// 预估字符串长度,指定初始容量
StringBuilder sb = new StringBuilder(1000); // 初始容量为 10003. 内存泄漏问题
症状:StringBuilder 或 StringBuffer 占用大量内存
解决方案:及时清空不需要的 StringBuilder 或 StringBuffer,或使用 setLength(0) 方法重置
示例:
java
StringBuilder sb = new StringBuilder();
// 使用 sb
...
// 重置 sb
sb.setLength(0);最佳实践
选择合适的类:
- 单线程环境:使用
StringBuilder(性能更好) - 多线程环境:使用
StringBuffer(线程安全)
- 单线程环境:使用
指定初始容量:根据预估的字符串长度,在创建时指定合适的初始容量,减少扩容操作
避免频繁创建:尽量重用
StringBuilder或StringBuffer对象,避免频繁创建新对象及时转换:当字符串不再需要修改时,及时调用
toString()方法转换为String对象注意线程安全:在多线程环境中,确保对
StringBuilder的操作是线程安全的合理使用方法:根据具体需求选择合适的方法,如
append()、insert()、delete()等
总结
StringBuilder 和 StringBuffer 是 Java 中用于处理可变字符串的类,它们的主要特点:
可变性:可以在不创建新对象的情况下修改字符串内容
性能:比
String类在字符串拼接和修改操作上性能更高区别:
StringBuilder:非线程安全,性能较高StringBuffer:线程安全,性能较低
应用场景:
- 大量字符串拼接
- 频繁的字符串修改操作
- 多线程环境(使用
StringBuffer)
通过合理使用 StringBuilder 和 StringBuffer,可以提高代码的性能和可维护性。
