CodeGym /课程 /JAVA 25 SELF /StringBuilder 与 StringBuffer

StringBuilder 与 StringBuffer

JAVA 25 SELF
第 9 级 , 课程 5
可用

1. 字符串的不可变性:朋友还是敌人?

在 Java 中,类 String不可变的(immutable)。这意味着创建之后就不能再更改该字符串。每次你“更改”字符串,例如通过 +concat() 追加内容,实际发生的是创建了一个新的对象,而旧对象则等待垃圾回收。

示例:

String s = "Hello";
s = s + " world!";
System.out.println(s); // Hello world!

看起来好像字符串变量 s 被修改了,但实际上创建了一个新的字符串 "Hello world!",而旧的 "Hello" 会留在内存中,直到被垃圾回收器清理。如果这样的操作很多——例如在循环中——程序会开始变慢并占用额外的内存。

想象你在搭一座积木塔,每次想加一块新积木,都得把整座塔重搭一遍。不太经济,对吧?在频繁修改时,Java 中普通的 String 就是这么工作的。

2. StringBuilder:快速的“字符串构建器”

StringBuilder(包 java.lang,无需导入)是用于高效构建和修改字符串的专用工具。它是可变的(mutable):可以追加、删除、插入字符和子串,而无需为每次操作都创建新对象。

类比:
如果 String 是一块混凝土板,那么 StringBuilder 就是 LEGO 积木:你可以反复添加或移除零件,而不必把全部拆了重来。

如何创建 StringBuilder

StringBuilder sb = new StringBuilder(); // 空
StringBuilder sb2 = new StringBuilder("初始值");

主要方法

方法 说明 用法示例
append(...)
在末尾追加字符串、数字、字符等。
sb.append("Java");
insert(index, ...)
在指定位置插入值
sb.insert(0, "Hello ");
delete(start, end)
删除从位置 start(含)到 end(不含)的字符
sb.delete(0, 5);
replace(start, end, str)
用其他内容替换字符串的一部分
sb.replace(0, 4, "Hi");
reverse()
将字符串反转
sb.reverse();
toString()
转换为普通字符串
String s = sb.toString();
setLength(newLen)
将长度裁剪或填充到指定值
sb.setLength(3);

使用示例

StringBuilder sb = new StringBuilder();
sb.append("你好,");
sb.append("世界!");
System.out.println(sb); // 你好,世界!

sb.insert(7, "Java "); // 在“你好,”之后插入 "Java "
System.out.println(sb); // 你好,Java 世界!

sb.replace(8, 12, "其他"); // 将 "Java" 替换为 "其他"
System.out.println(sb); // 你好,其他世界!

sb.reverse();
System.out.println(sb); // !界世他其,好你

3. StringBuffer:带有线程安全的“老大哥”

StringBuilderStringBuffer 有什么区别?

  • StringBuilder:更快,但不是线程安全的(未同步)。
  • StringBuffer:速度较慢,但线程安全(已同步)。

如果你的应用在单线程下工作——请使用 StringBuilder(更快)。如果多个线程可能修改同一段字符串——请使用 StringBuffer

4. 何时使用 StringBuilder 而不是 String?

场景

  • 在循环中或拼接大文本时对字符串进行频繁修改(追加、删除、插入)。
  • 从数组/列表构建字符串(CSV、HTML、报告等)。
  • 解析与文本处理,涉及大量字符串操作。

示例:从数组构建字符串

不推荐的方式(使用 String+):

String[] names = {"伊万", "彼得", "玛丽娅"};
String result = "";

for (int i = 0; i < names.length; i++) 
{
    result += names[i];
    if (i < names.length - 1) 
    {
        result += ", ";
    }
}
System.out.println(result);

推荐的方式(使用 StringBuilder):

String[] names = {"伊万", "彼得", "玛丽娅"};
StringBuilder sb = new StringBuilder();

for (int i = 0; i < names.length; i++) 
{
    sb.append(names[i]);
    if (i < names.length - 1) 
    {
        sb.append(", ");
    }
}
System.out.println(sb.toString());

差异:第一种方式每一步都会创建一个新字符串,第二种方式则是在同一个 StringBuilder 对象上累积构建。

5. 性能对比:String vs StringBuilder


// 通过 String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
    s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " 毫秒");

// 通过 StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
    sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " 毫秒");

结论:在大多数情况下,进行多次连接时,StringBuilder 的速度要快得多。

6. 实用细节

能用 String 的方法吗?
StringBuilder 有自己的方法。若要得到字符串——请调用 toString()

StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString(); // 现在 s 是普通字符串

能用 equals 比较 StringBuilder 吗?
注意:sb1.equals(sb2) 比较的是引用而非内容。请这样比较:

if (sb1.toString().equals(sb2.toString())) 
{
    // 内容相同
}

可以把 StringBuilder 传给 System.out.println 吗?
可以。System.out.println 会自动调用 toString()

可以按索引读取字符吗?
可以,使用 charAt(int index),与普通字符串相同。

7. 使用 StringBuilder 和 StringBuffer 时的常见错误

错误 1:equals 或运算符 == 比较两个 StringBuilder。这些检查比较的是引用而非内容。请使用 toString() 后再比较字符串。

错误 2:在需要 String 的地方(从方法返回、日志记录、传给 API)忘记调用 toString()

错误 3:为两三次简单的连接就使用 StringBuilder。像 "Hello, " + name 这样的写法可读且高效。

错误 4:在循环中通过 + 连接 String。这在时间和内存上都不高效——请使用 StringBuilder

错误 5:在没有必要时混淆 StringBufferStringBuilder。如果没有来自多个线程的并发修改——请选择 StringBuilder

错误 6:不加思考地用 setLength() 裁剪 StringBuilder 的内容。请确保新长度正确,超过该长度的数据将被丢弃。

1
调查/小测验
字符串操作第 9 级,课程 5
不可用
字符串操作
字符串操作
评论 (3)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
ncksllpo 级别 42,Cherkasy,Ukraine
11 一月 2026
ncksllpo 级别 42,Cherkasy,Ukraine
11 一月 2026
这里似乎出现了一些问题
ncksllpo 级别 42,Cherkasy,Ukraine
11 一月 2026
6,7行的代码