核心概念

特性 String StringBuffer
可变性 ❌ 不可变(Immutable) ✅ 可变(Mutable)
线程安全 ✅ 天然线程安全(因不可变) ✅ 线程安全(方法用 synchronized 修饰)
性能 ⚠️ 频繁修改时效率低(产生大量中间对象) ✅ 频繁修改时效率高(原地修改)
存储位置 字符串常量池 堆内存
适用场景 字符串不经常修改 字符串频繁修改(尤其多线程环境)

操作步骤详解(StringBuffer)

1. 创建对象

// 空对象(初始容量16字符)
StringBuffer sb1 = new StringBuffer();

// 指定初始容量(避免频繁扩容)
StringBuffer sb2 = new StringBuffer(100); 

// 用字符串初始化
StringBuffer sb3 = new StringBuffer("Hello");

2. 追加内容(append()

sb1.append("Java");        // 追加字符串
sb1.append(11);            // 追加int → "Java11"
sb1.append('!');           // 追加char → "Java11!"
sb1.append(true);          // 追加boolean → "Java11!true"

3. 插入内容(insert()

sb1.insert(4, "Script");   // 索引4处插入 → "JavaScript11!true"

4. 删除内容(delete()/deleteCharAt()

sb1.delete(10, 15);        // 删除[10,15) → "JavaScript"
sb1.deleteCharAt(9);       // 删除索引9的字符 → "JavaScrip"

5. 替换内容(replace()

sb1.replace(0, 4, "Type"); // [0,4)替换为"Type" → "TypeScrip"

6. 反转字符串(reverse()

sb1.reverse();             // → "pirScpyT"

7. 转换为String(toString()

String result = sb1.toString(); // "pirScpyT"

8. 其他关键操作

int len = sb1.length();     // 获取长度
int cap = sb1.capacity();   // 获取当前容量
sb1.setLength(5);           // 设置长度(截断/补空字符)
sb1.trimToSize();           // 释放多余容量(节省内存)

常见错误

  1. 混淆不可变性
    String s = "A";
    s.concat("B"); // 错误!s仍为"A"(需赋值:s = s.concat("B");)
    
  2. 误用String拼接大对象
    // 错误:循环中String拼接产生大量垃圾对象
    String s = "";
    for (int i = 0; i < 10000; i++) {
        s += i; // 每次循环new StringBuilder→拼接→toString
    }
    
  3. 索引越界
    StringBuffer sb = new StringBuffer("Hi");
    sb.insert(5, "!"); // StringIndexOutOfBoundsException
    

注意事项

  1. 线程安全代价
    StringBuffer 的同步锁在单线程下是性能损耗,此时应用 StringBuilder(非线程安全,但速度更快)。
  2. 初始容量设置
    预估最终长度并设置初始容量(如 new StringBuffer(1000)),避免多次扩容(默认扩容:(旧容量+1)*2)。
  3. 避免频繁toString()
    多次调用 toString() 会生成新String对象,应在最终需要时调用。

使用技巧

  1. 链式调用(因方法返回 this
    sb.append("A").insert(1, "B").reverse();
    
  2. 清空缓冲区
    sb.setLength(0); // 重用对象(避免new)
    
  3. 单线程优化
    StringBuilder 替代(API相同,性能提升10%~15%)。

最佳实践与性能优化

场景选择

场景 推荐类
字符串常量(如配置Key) String
单线程字符串频繁修改 StringBuilder
多线程字符串频繁修改 StringBuffer

性能关键点

  1. 拼接大字符串
    // ✅ 正确做法(预分配容量)
    StringBuffer sb = new StringBuffer(10000);
    for (int i = 0; i < 5000; i++) {
        sb.append(i); // 无额外对象产生
    }
    
  2. 避免无谓转换
    // ❌ 低效
    String s = "A" + 1 + "B"; // 编译为 new StringBuilder().append("A").append(1).append("B")
    
    // ✅ 直接使用StringBuilder/Buffer
    sb.append("A").append(1).append("B");
    
  3. 复用对象
    在循环外部创建 StringBuffer,避免每次循环新建。

总结

决策因素 选择
字符串不修改 String
单线程频繁修改 StringBuilder
多线程频繁修改 StringBuffer
内存敏感场景 预分配容量 + 复用

实践口诀

“不变用String,单线程改用Builder,多线程改用Buffer,预分配容量效率高!”