Java StringBuffer 与 StringBuilder

String 的内容不可变,每次用 + 拼接都会新建对象,循环里大量拼接既慢又费内存。为此 Java 提供了可变的 StringBuffer 与 StringBuilder,能直接在原对象上增删改。

为什么需要可变字符串

用 + 拼接字符串时,每拼接一次就产生一个新的 String,循环次数多了开销很大:

public class SlowConcat {
    public static void main(String[] args) {
        String s = "";
        for (int i = 0; i < 10000; i++) {
            s = s + i;   // 每轮都新建一个 String 对象,旧对象等待回收
        }
        System.out.println(s.length());   // 输出:38890
    }
}

String、StringBuffer、StringBuilder 的区别

类型内容可否修改线程安全速度适用场景
String不可变安全慢(拼接时)内容固定、少量拼接
StringBuffer可变安全(方法加锁)较快多线程环境拼接
StringBuilder可变不安全最快单线程拼接(首选)

单线程拼接优先用 StringBuilder;StringBuffer 与它 API 完全一致,只是方法加了 synchronized,多线程共享时才需要。

StringBuilder 基本用法

// 片段需放进 main 方法中运行
StringBuilder sb = new StringBuilder("Hello");
sb.append(" Java");          // 末尾追加
sb.insert(5, ",");           // 在下标 5 处插入
sb.delete(5, 6);             // 删除 [5, 6) 区间,即刚插入的逗号
sb.replace(0, 5, "Hi");      // 用 "Hi" 替换 [0, 5)
System.out.println(sb);      // 输出:Hi Java

常用方法一览

方法作用
append(x)末尾追加任意类型
insert(i, x)在指定下标插入
delete(a, b)删除 [a, b) 区间
deleteCharAt(i)删除单个字符
replace(a, b, s)区间替换
reverse()内容反转
setLength(n)截断或扩容到长度 n
charAt(i) / length()取值 / 取长度
toString()转成不可变的 String

完整可运行示例

把上面的方法串起来,直接编译运行看效果:

public class StringBuilderDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" Java");          // 追加
        System.out.println(sb);      // 输出:Hello Java
        sb.insert(5, ",");           // 插入逗号
        System.out.println(sb);      // 输出:Hello, Java
        sb.delete(5, 6);             // 删掉逗号
        System.out.println(sb);      // 输出:Hello Java
        sb.setLength(5);             // 只保留前 5 个字符
        System.out.println(sb);      // 输出:Hello
        sb.reverse();                // 反转
        System.out.println(sb);      // 输出:olleH
        String result = sb.toString().toUpperCase();
        System.out.println(result);  // 输出:OLLEH
    }
}

拼接性能对比

同样的拼接任务,StringBuilder 明显更快:

public class SpeedCompare {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100000; i++) {
            sb.append("a");   // 原地修改,不产生中间对象
        }
        long cost = System.currentTimeMillis() - start;
        System.out.println("StringBuilder 耗时:" + cost + " 毫秒");
    }
}

小结:要反复拼接、删除、插入字符串时,忘掉 +,改用 StringBuilder(单线程首选);多线程共享可变字符串时再换成线程安全的 StringBuffer。两者方法几乎相同,可互相替换。

笔记加载中…