| 特性 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 可變性 | 不可變 | 可變 | 可變 |
| 執行緒安全 | 天然安全 | 同步化 (安全) | 非同步 (不安全) |
| 繼承關係 | final class | extends AbstractStringBuilder | extends AbstractStringBuilder |
| 記憶體行為 | 每次修改建立新物件 | 擴容機制 (預設 16 字元,滿時 2倍+2) | 同 StringBuffer |
| 適用場景 | 常量、少量拼接、多執行緒共享 | 多執行緒大量字串操作 | 單執行緒大量字串操作 (推薦) |
// 反編譯視角
String a = "hello";
a += " world";
// 實際編譯為:
StringBuilder sb = new StringBuilder("hello");
sb.append(" world");
a = sb.toString();
每次拼接產生新 StringBuilder → append → toString() 新 String,舊物件等待 GC。
// JDK 8 實作片段
public AbstractStringBuilder append(String str) {
ensureCapacityInternal(count + str.length());
// ...
}
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value, newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
return (value.length << 1) + 2; // 2倍 + 2
}
public class StringPerfTest {
public static void main(String[] args) {
int iterations = 10_000;
// String +=
long start = System.currentTimeMillis();
String s = "";
for (int i = 0; i < iterations; i++) s += i;
System.out.println("String += : " + (System.currentTimeMillis() - start) + " ms");
// StringBuffer
start = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < iterations; i++) sb.append(i);
System.out.println("StringBuffer: " + (System.currentTimeMillis() - start) + " ms");
// StringBuilder (單執行緒首選)
start = System.currentTimeMillis();
StringBuilder sbl = new StringBuilder();
for (int i = 0; i < iterations; i++) sbl.append(i);
System.out.println("StringBuilder: " + (System.currentTimeMillis() - start) + " ms");
}
}
String += : 1,245 ms StringBuffer: 2 ms StringBuilder: 1 ms
| 操作 | String | StringBuffer/Builder |
|---|---|---|
| 追加 | concat() / + | append() |
| 插入 | 無 | insert(index, str) |
| 刪除 | 無 | delete(start, end) |
| 反轉 | 無 | reverse() |
| 查詢包含 | contains() ✓ | indexOf() ≠ -1 |
| 轉字串 | 本身 | toString() |
StringBuilder (JDK 5+ 首選)StringBufferString.format()、MessageFormatString.join() (JDK 8+)、Collectors.joining()+,編譯器優化為單一字串String +=substring() 大字串 (JDK 7+ 已修復共享 char[] 問題,但仍建議謹慎)new String("literal")
// 預估最終長度約 50,000 字元
StringBuilder sb = new StringBuilder(50_000);
for (int i = 0; i < 10_000; i++) {
sb.append("Item").append(i).append(';');
}
預分配容量可消除擴容複製開銷,效能再提升 10-20%。
String 不可變是設計而非缺陷,保證執行緒安全、字串常量池共享、安全性敏感場景不可篡改。StringBuilder 是單執行緒字串操作的標準選擇,StringBuffer 保留給少數多執行緒共享緩衝區場景。理解底層 char[]/byte[] (JDK 9+ Compact Strings) 擴容機制,預估容量、選對工具,才能寫出高效能 Java 程式碼。