老生常談的一句話 “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的臨時對象,會顯著節省時間。
