何时使用 String, StringBuffer, StringBuilder

本文深入探讨了在编程中进行字符串串联时,使用String的'+'操作符、StringBuffer的append()方法和StringBuilder的append()方法之间的性能差异。通过分析循环控制语句中的大量串联操作,阐述了采用StringBuffer或StringBuilder可以有效节省内存和CPU资源,避免不必要的对象创建和垃圾回收开销。同时,文章指出了选择不同方法时应考虑的因素,包括程序的可读性和性能需求。
性能分析:

在进行字符串串联操作时(串联的不光是字符串类型)我们有三种选择:
  1. 采用 String 的 '+' 操作符;
  2. 采用 StringBuffer.append() 方法;
  3. 采用 StringBuilder.append() 方法;
实际上 2 和 3 差不多,只不过 StringBuilder 不是线程安全的,在讨论本文问题时可以只讨论其一,我们以 StringBuffer 为例。

两种串联方法最大的区别在于性能上,使用 String 的 ‘+’ 操作符相比 StringBuffer 的 append() 方法是低效的,突出表现在循环控制语句中需要大量进行字符串串联的情况下。考虑下面的代码:
String contents = "";
String line;

while ( (line=reader.readLine()) != null)
{
    contents += line+"\n";
}
它相当于进行了下面的操作:
String contents = "";
String line;

while ( (line=reader.readLine()) != null)
{
    contents = new StringBuffer (contents).append(line).append("\n").toString();
}
在每一级循环中都会创建一个新的对象,且保存一个新创建的字符串,垃圾回收器不会及时回收这些已经利用过的字符串,于是内存中的字符串数据呈等差数列和增长,空间复杂度达到 O(n^2);而创建的冗余字符串对象也牺牲了CPU资源,耗时增加。

解决以上低效问题的途径是采用 StringBuffer 或者 StringBuilder 的 append() 方法,其空间是按需动态追加的,不会产生过多冗余的字符串,从而节省了内存,由于整个循环只需要一个 StringBuffer 或 StringBuilder 对象,所以也不会产生冗余的CPU消耗,节省了时间,改进后的版本如下:
String contents = "";
String line;
StringBuffer buffer = new StringBuffer();
while ( (line=reader.readLine()) != null)
{
    buffer.append(line).append("\n");
}
contents = buffer.toString();

总结:
  1. 如果需要大量地遍历进行字符串串联,则性能是首要需要考虑的,此时采用 StringBuffer 或者 StringBuilder;
  2. 否则,考虑到程序的可读性,应该使用 String 的 '+' 操作符,这时性能差别可以忽略不计;
  3. StringBuffer 和 StringBuilder 的区别在于 StringBuffer 是线程安全的,StringBuilder 则不然。

参考:
谷歌工程师 Jon Skeet 的定量分析: http://www.yoda.arachsys.com/java/strings.html
### StringStringBuffer StringBuilder使用场景及区别 #### 1. **String 类** `String` 是 Java 中用于表示不可变字符串的核心类。一旦创建了 `String` 对象,其内容就不能更改[^1]。每次对 `String` 进行修改操作(如拼接、替换)时,都会生成一个新的 `String` 对象,并将旧对象丢弃。 **特点:** - 不可变性:字符串的内容一旦创建就无法更改。 - 线程安全:由于不可变性,`String` 在多线程环境中是天然线程安全的。 - 性能影响:频繁修改会导致大量中间对象产生,增加内存开销垃圾回收压力。 **适用场景:** - 字符串内容不需要频繁修改的情况。 - 多线程环境下需要共享字符串数据且不希望引入额外同步机制的场景。 **示例代码:** ```java String str = "Hello"; str += " World"; // 创建新的 String 对象 ``` #### 2. **StringBuffer 类** `StringBuffer` 是一个可变字符串类,并且是线程安全的。它内部通过同步方法(synchronized)来保证在多线程环境下的安全性[^2]。 **特点:** - 可变性:可以在原有对象基础上进行修改,避免频繁创建新对象。 - 线程安全:所有公共方法都使用 `synchronized` 关键字修饰,适合多线程并发访问。 - 性能相对较低:由于同步机制的存在,在单线程环境下性能不如 `StringBuilder`。 **适用场景:** - 需要频繁修改字符串内容。 - 多线程环境下需要共享缓冲区并进行字符串操作。 **示例代码:** ```java StringBuffer sb = new StringBuffer("Hello"); sb.append(" World"); // 修改原对象 ``` #### 3. **StringBuilder 类** `StringBuilder` 是从 Java 5 引入的可变字符串类,功能与 `StringBuffer` 相同,但它是非线程安全的[^3]。 **特点:** - 可变性:允许在原有对象上进行修改。 - 非线程安全:没有同步机制,适用于单线程环境。 - 性能高:相比 `StringBuffer`,在单线程中执行更快。 **适用场景:** - 需要频繁修改字符串内容。 - 单线程环境下,追求高性能的操作。 **示例代码:** ```java StringBuilder sb = new StringBuilder("Hello"); sb.append(" World"); // 修改原对象 ``` ### 总结对比 | 特性 | String | StringBuffer | StringBuilder | |------------------|----------------|----------------|----------------| | 可变性 | 不可变 | 可变 | 可变 | | 线程安全性 | 线程安全 | 线程安全 | 非线程安全 | | 性能 | 较低 | 中等 | 最高 | | 适用环境 | 不常修改字符串 | 多线程修改 | 单线程修改 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值