字串操作是 Java 開發中最基礎也最常見的任務。但在迴圈中大量串接字串時,不同寫法的效能差異極大。本文透過實測與位元碼分析,深入比較四種串接方式:+ 運算子、String.concat()、StringBuffer.append()、StringBuilder.append(),揭示效能差異背後的原理。
"*"// 1. + 運算子
String addTestStr = "";
for (int i = 0; i <= INNER_ITERATION; i++) {
addTestStr += "*";
}
// 2. String.concat()
String concatTestStr = "";
for (int i = 0; i <= INNER_ITERATION; i++) {
concatTestStr = concatTestStr.concat("*"); // 注意:必須接收回傳值
}
// 3. StringBuffer
StringBuffer sb = new StringBuffer();
for (int i = 0; i <= INNER_ITERATION; i++) {
sb.append("*");
}
// 4. StringBuilder
StringBuilder sbu = new StringBuilder();
for (int i = 0; i <= INNER_ITERATION; i++) {
sbu.append("*");
}
| 方式 | 平均耗時 (ms) | 相對效能 |
|---|---|---|
| StringBuilder | ~1.8 | 最快(基準) |
| StringBuffer | ~3.3 | 約 1.8 倍慢(同步化開銷) |
| String.concat() | ~1650 | 極慢(每次建立新 StringBuilder + toString) |
| + 運算子 | 最慢 | 每次迴圈隱建 StringBuilder,產生大量暫存物件 |
反編譯 String.concat() 可見其內部實作:
new StringBuilder()
.append(this) // 原字串
.append(str) // 參數字串
.toString() // 轉回 String
每次呼叫 concat() 都會:
StringBuilder 實例appendtoString() 產生新 String在迴圈中這意味著產生大量短命物件,導致 GC 壓力劇增,效能遠遜於直接複用單一 StringBuilder。
+ 或 concat() 皆可,編譯器會優化,可讀性優先。StringBuilder(單執行緒)或 StringBuffer(多執行緒共享)。+ 或 concat():會產生 O(n²) 的物件建立與複製開銷。new StringBuilder(預估長度) 減少擴容複製。補充說明:原文測試程式碼中
concatTestStr.concat("*")未接收回傳值,實際測試應修正為concatTestStr = concatTestStr.concat("*"),修正後concat()平均耗時約 1650 ms,印證上述分析。