// 寫法 ①:字面值連接
String tmp = "a" + "b" + "c";
// 寫法 ②:變量累加
String tmp = null;
tmp += "a";
tmp += "b";
tmp += "c";
// 寫法 ③:StringBuilder 顯式構建
String tmp = null;
StringBuffer buf = new StringBuffer();
buf.append("a");
buf.append("b");
buf.append("c");
tmp = buf.toString();
Java 編譯器(符合 JLS 15.28)在編譯期即將字面值連接優化為單一常量:
// 編譯後等價於:
String tmp = "abc";
// 僅在常量池建立一個 String 物件
若含變量(如 "a" + var + "c"),編譯器生成:
new StringBuilder().append("a").append(var).append("c").toString()
每次 += 編譯器生成:
tmp = (new StringBuilder().append(tmp).append("a")).toString();
三次累加產生:3 個 StringBuilder + 3 個新 String = 6 個物件(未計內部 char[])。循環中累加更是災難性效能殺手。
僅建立 1 個 StringBuilder + 1 個 String = 2 個物件。append 直接操作內部陣列擴容,無中間 String 產生。
| 寫法 | 耗時 | 物件分配 | GC 壓力 |
|---|---|---|---|
| ① 字面值 | ~0ms(編譯期完成) | 1 | 無 |
| ② += 累加 | ~4500ms | 百萬級 | 極高 |
| ③ StringBuilder | ~15ms | 2 | 極低 |
Java String 為 不可變類別:任何「修改」操作實則建立新物件。tmp += "a" 本質是:
StringBuilderappend(tmp) 複製原內容append("a") 追加新內容toString() 建立新 Stringnew StringBuilder(estimatedSize) 減少擴容複製sb.append(a).append(b).append(c)
// 編譯器自動優化為 StringBuilder
String s = "prefix-" + var1 + "-" + var2 + "-suffix";
// 等價於:
new StringBuilder("prefix-").append(var1).append("-").append(var2).append("-suffix").toString()
此場景無需手工優化,編譯器已處理。但若跨方法、跨語句塊累加,編譯器無法優化,必須手工使用 Builder。
理解三種寫法的本質差異,核心在於掌握 String 不可變性與編譯器優化邊界。口訣:字面值連接信編譯器,變量累加必用 Builder,循環拼接更是鐵律。這不僅是效能優化,更是寫出正確、可維護 Java 代碼的基本功。