字串操作是 Java 開發最高頻操作之一。String 不可變、StringBuilder 非線程安全、StringBuffer 線程安全,三者效能差異巨大。本文透過基準測試數據、原始碼分析、使用場景建議,幫助開發者做出正確選型。
StringBuilder > StringBuffer > String
| 特性 | String | StringBuilder | StringBuffer |
|---|---|---|---|
| 可變性 | 不可變 | 可變 | 可變 |
| 線程安全 | 是 (不可變天然安全) | 否 | 是 (synchronized) |
| 繼承關係 | final class | extends AbstractStringBuilder | extends AbstractStringBuilder |
| Java 版本 | 1.0 | 5.0 | 1.0 |
| 適用場景 | 常量、少量拼接 | 單線程大量拼接 | 多線程共享拼接 |
String s = "a";
s += "b"; // 實際發生:
// 1. 建立 StringBuilder
// 2. append("a")
// 3. append("b")
// 4. toString() 產生新 String
// 5. 原 "a" 等待 GC
循環拼接 N 次會產生 N 個中間物件,時間複雜度 O(N²),記憶體壓力大。
兩者皆繼承 AbstractStringBuilder,核心欄位:
char[] value; // 字元陣列
int count; // 實際長度
append() 直接在陣列尾端寫入,容量不足時擴容 (約 2倍 + 2),時間複雜度 O(N)。
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
所有公共方法皆加 synchronized,多線程安全但效能損耗約 10-30%。
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class StringConcatBenchmark {
@Benchmark
public String stringConcat() {
String s = "";
for (int i = 0; i < 1_000_000; i++) s += "x";
return s;
}
@Benchmark
public String builderConcat() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1_000_000; i++) sb.append("x");
return sb.toString();
}
@Benchmark
public String bufferConcat() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 1_000_000; i++) sb.append("x");
return sb.toString();
}
}
stringConcat ~ 45,000 ms (O(N²) 災難) bufferConcat ~ 120 ms (同步開銷) builderConcat ~ 90 ms (最快)
StringBuilder,多線程用 StringBuffer 或 ThreadLocalnew StringBuilder(1024) 減少擴容次數String.format() / StringBuilder.append() 替代複雜拼接list.stream().collect(Collectors.joining(",")) 簡潔高效+StringBuilder 是 95% 場景的正解。只有確定有多線程併發存取同一建構器時才用 StringBuffer。理解不可變與可變、同步與非同步的權衡,能寫出高效能、低 GC 壓力的 Java 程式碼。
java.lang.AbstractStringBuilder