StringBuffer vs StringBuilder:Java字符串处理终极指南

5 阅读3分钟

📌 StringBuffer vs StringBuilder:Java字符串处理终极指南

#Java基础 #字符串处理 #性能优化 #面试必备


一、核心区别:线程安全与性能取舍

特性StringBufferStringBuilder
线程安全✅ 所有方法同步(synchronized)❌ 非线程安全
性能较低(同步开销)较高(无同步开销)
JDK版本1.0+1.5+
适用场景多线程环境单线程环境

二、底层原理揭秘

1. 继承关系

public final class StringBuffer
    extends AbstractStringBuilder
    implements Serializable, Comparable<StringBuffer>, CharSequence

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, Comparable<StringBuilder>, CharSequence

两者共享同一父类AbstractStringBuilder,底层均使用可扩容的char数组实现。

2. 扩容机制

  • 初始容量:16字符
  • 扩容规则:新容量 = (原容量 * 2) + 2
  • 触发条件:当前长度+新内容长度 > 当前容量

三、常用方法实战(两者API完全一致)

1. 初始化与容量控制

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

// 获取当前容量
int capacity = sb.capacity();

// 主动扩容
sb.ensureCapacity(200);

2. 增删改查操作

// 追加内容(支持链式调用)
sb.append("Hello").append(" ").append(2024);

// 指定位置插入
sb.insert(5, " World");  // Hello World 2024

// 删除子串
sb.delete(0, 6);  // World 2024

// 替换内容
sb.replace(6, 10, "Java");  // World Java

// 反转字符串
sb.reverse();  // avaJ dlroW

// 清空缓冲区
sb.setLength(0);

3. 字符串转换

// 转String对象
String result = sb.toString();

// 截取子串(不影响原对象)
String sub = sb.substring(0, 5);

// 获取指定位置字符
char ch = sb.charAt(2);

四、性能对比测试

public class PerformanceTest {
    public static void main(String[] args) {
        int loopCount = 100000;

        // StringBuilder测试
        long start1 = System.nanoTime();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < loopCount; i++) {
            sb.append(i);
        }
        long time1 = System.nanoTime() - start1;

        // StringBuffer测试
        long start2 = System.nanoTime();
        StringBuffer sf = new StringBuffer();
        for (int i = 0; i < loopCount; i++) {
            sf.append(i);
        }
        long time2 = System.nanoTime() - start2;

        System.out.printf("StringBuilder耗时:%.2fms%n", time1/1e6);
        System.out.printf("StringBuffer耗时:%.2fms%n", time2/1e6);
    }
}

/* 典型输出:
   StringBuilder耗时:3.15ms
   StringBuffer耗时:8.74ms */

五、开发最佳实践

  1. 单线程环境必选StringBuilder 循环体内字符串拼接、日志构建等场景优先使用。

  2. 预估初始容量 避免频繁扩容,提升性能:

    // 错误示范:默认容量16
    StringBuilder sb = new StringBuilder();
    
    // 正确做法:预估最终长度
    StringBuilder sb = new StringBuilder(1024);
    
  3. 避免与String混用 错误示例:

    String str = "";
    for (int i=0; i<10000; i++) {
        str += i;  // 每次循环创建新StringBuilder对象
    }
    

    正确优化:

    StringBuilder sb = new StringBuilder();
    for (int i=0; i<10000; i++) {
        sb.append(i);
    }
    String str = sb.toString();
    

六、高频面试题解析

Q1:为什么StringBuilder比StringBuffer快? 👉 省去synchronized同步锁的开销,减少线程竞争带来的性能损耗。

Q2:两者是否都实现Serializable接口? 👉 是,但实际序列化时需要自定义writeObject/readObject方法处理char数组。

Q3:如何实现线程安全的StringBuilder? 👉 方案一:使用Collections.synchronizedList包装 👉 方案二:自定义同步方法(不推荐,应直接使用StringBuffer)


七、总结选择策略

场景推荐类理由
单线程字符串操作StringBuilder性能最优
多线程共享字符串操作StringBuffer保证线程安全
方法局部变量StringBuilderJVM栈封闭,天然线程安全
静态变量/类成员变量StringBuffer可能被多线程访问