【实例描述】
字符串是程序开发中使用最频繁的数据,在Java 中字符串是String 类的对象,它是不可变数据,当执行字符串连接操作时将生成新的字符串,而不是修改原有的字符串,所以大量的字符串操作非常耗时。本实例将分别演示使用String 类与StringBuilder 类进行3 万个字符串追加的操作,并输出其运行时间。我们可以对比两次方法执行的时间。运行效果如图4.26 所示。
【实现过程】
在Eclipse 中新建项目BuilderString,并在其中创建一个BuilderString.java 文件。在该类的主方法中创建字符串对象appendStr,并通过循环为该字符串连接3 万个字符,计算并输出其用时。再创建StringBuilder 字符串构造器,同样为其追加3 万个字符,计算并输出其用时。核心代码如下所示:
public class BuilderString {
public static void main(String[] args) {
String appendStr = ""; // 创建字符串变量
long startTime = System.nanoTime(); // 开始记事
for (int i = 20000; i < 50000; i++) { // 遍历30000 个字符
appendStr += (char) i; // 字符串与每个字符执行连接操作
}
long endTime = System.nanoTime(); // 结束计时
System.out.println("String 追加字符3 万个。");
// 输出用时
System.out.println("用时:" + (endTime - startTime) / 1000000d + "毫秒
");
StringBuilder strBuilder = new StringBuilder(); // 创建字符串构建器
startTime = System.nanoTime(); // 开始计时
for (int i = 20000; i < 50000; i++) { // 遍历30000 个字符
strBuilder.append((char) i); // 把每个字符追加到构建器
}
endTime = System.nanoTime(); // 结束计时
System.out.println("StringBuilder 字符串构建器追加字符3 万个。");
// 输出用时
System.out.print("用时:" + (endTime - startTime) / 1000000d + "毫秒");
}
}
【代码解析】
从JDK 5.0 开始,Java 增添了一个单个线程使用的等价类,即StringBuilder。通常应该优先使用StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。但是,如果将StringBuilder 的实例用于多个线程是不安全的,这时我们则建议使用StringBuffer。
【知识扩展】
在性能强弱上:StringBuilder>StringBuffer>String。有关这三者的性能问题我们再提示以下几点:
1. 为了获得更好的性能,在构造StringBuffer 或StringBuilder 时应尽可能指定它的容量。当然,如果你操作的字符串长度不超过16 个字符就不用了。
2. 相同情况下使用StringBuilder 与使用StringBuffer 相比,仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此,除非能确定你的系统瓶颈是在StringBuffer 上,并且确定你的模块不会运行在多线程模式下,否则还是用StringBuffer。
3. 用好现有的类比引入新的类更重要。很多程序员在使用StringBuffer 时是不指定其容量的,如果这样的习惯带StringBuilder 的使用中,只能获得10%左右的性能提升;但如果使用指定容量的StringBuffer,将马上获得45%左右的性能提升,甚至比不使用指定容量的StringBuilder 快30%左右。