老生常谈的一句话 “StringBuilder在拼接字符串时效率更高”。
所以笔者写了如下测试代码
1 public static void main(String[] args) { 2 String s1 = "Hello"; 3 String s2 = "World"; 4 long st = System.currentTimeMillis(); 5 for (int i = 0; i < 100000; i++) { 6 s1+=s2; 7 } 8 long en = System.currentTimeMillis(); 9 System.out.println(en-st); 10 11 StringBuffer sb1 = new StringBuffer("Hello"); 12 String sb2 = "World"; 13 long st1 = System.currentTimeMillis(); 14 for (int i = 0; i < 100000; i++) { 15 sb1.append(sb2); 16 } 17 long en1 = System.currentTimeMillis(); 18 System.out.println(en1-st1); 19 20 }
结果显示,时间相差了几千倍之多
32702 11
心中一丝困惑潜滋暗长,几十秒的差距,时间损耗在哪里呢?
在《java程序员面试宝典》这本书中,我找到如下这段话
所以由此可见,时间损耗在了循环中 底层新建 StringBuffer对象的过程中。但笔者再次发现,有的博文中说 底层用的是StringBuilder。
于是我在查阅资料的过程中发现了“反编译”这一操作
(用编译好的字节码文件)执行如下操作
javap -v Demo.class
得到一串反编译后的代码(截取部分)
5: new #3 // class java/lang/StringBuilder 8: dup 9: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 12: aload_1 13: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: aload_2 17: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 23: astore_1 24: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 27: aload_1 28: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
所以 可以确定,至少在此段代码所在版本(jdk1.8),底层调用的是StringBuilder的append()方法
经过再次查证
得出了阶段性的结论
String拼接字符串操作,底层新建了StringBuffer对象,并调用了它的append()方法 和toString()方法
在jdk1.5之后,将其更新成了StringBuilder进行此操作。
所以如果遇到了大量字符串拼接的场景,可以手动创建StringBuilder的临时对象,会显著节省时间。