首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 字串處理三大核心類深度解析:String、StringBuffer、StringBuilder

     編輯:Java 相關知識

前言

String、StringBuffer、StringBuilder 是 Java 開發者每天都在使用的類別,但真正理解其底層機制、效能差異與適用場景的開發者並不多。本文從記憶體模型、JVM 編譯優化、實戰基準測試三個維度,徹底講透這三兄弟。

一、核心特性速查表

特性StringStringBufferStringBuilder
可變性不可變可變可變
執行緒安全天生安全同步鎖保護非安全
繼承關係final classextends AbstractStringBuilderextends AbstractStringBuilder
引入版本JDK 1.0JDK 1.0JDK 1.5
底層儲存char[] / byte[] (JDK 9+)char[] / byte[]char[] / byte[]

二、記憶體模型與操作機制

String:不可變帶來的代價

String s = "a";
s += "b";  // 實際發生:
// 1. new StringBuilder("a")
// 2. append("b")
// 3. toString() → 新 String 物件
// 4. 原 "a" 變成垃圾等待 GC

每次修改都產生新物件,頻繁操作會造成:

  • 大量短命物件佔據 Eden 區
  • 觸發 Minor GC 甚至 Full GC
  • 記憶體碎片化

StringBuffer/Builder:可變字元陣列

內部維護 char[] value(JDK 9+ 改為 byte[] + coder)與 int count:

  • append:確保容量 → 複製資料 → 更新 count
  • 擴容策略:newCapacity = (oldCapacity + 1) * 2
  • 無新物件產生,僅陣列複製

三、JVM 編譯期優化:+ 號的真相

單一敘述:零成本語法糖

// 源碼
String s = "Hello" + name + "!";

// javac 編譯後 (javap -c)
new StringBuilder()
  .append("Hello")
  .append(name)
  .append("!")
  .toString()

編譯器自動插入 StringBuilder,**單行拼接完全無效能損失**。

常量摺疊:編譯期直接計算

String s = "A" + "B" + "C";  // 編譯期直接變 "ABC"
String s = "A" + "B" + var;  // 編譯期合併常量:"AB" + var

迴圈/多行:編譯器無能為力

// 源碼
String s = "";
for (int i=0; i<100; i++) s += i;

// 位元碼:迴圈內每次 new StringBuilder → 災難

四、效能實測數據(JMH 基準測試參考)

Benchmark                          Mode  Cnt     Score    Error  Units
StringConcat.singleStatement      thrpt   10  12,450 ±  320  ops/ms
StringConcat.loopPlus             thrpt   10     320 ±   15  ops/ms
StringConcat.loopStringBuilder    thrpt   10  11,800 ±  280  ops/ms
StringConcat.loopStringBuffer     thrpt   10   9,200 ±  210  ops/ms

關鍵發現:

  • 單行 + 號 ≈ 顯式 StringBuilder
  • 迴圈 + 號比 StringBuilder **慢 30-40 倍**
  • StringBuilder 比 StringBuffer **快 20-30%**(無鎖優勢)

五、適用場景決策樹

需要修改字串內容?
├─ 否 → 直接用 String(常量、參數傳遞、金鑰值)
└─ 是 → 多執行緒共享同一緩衝區?
        ├─ 是 → StringBuffer(極少見,通常用 ThreadLocal + StringBuilder)
        └─ 否 → 單執行緒 / 區域變數 → StringBuilder
                ├─ 可預估最終長度 → new StringBuilder(estimatedCapacity)
                ├─ 大量單字元 append → sb.append('c') 而非 sb.append("c")
                └─ 最終輸出前保持 StringBuilder 型態,避免過早 toString()

六、JDK 9+ Compact Strings 變革

JDK 9 引入 byte[] value + byte coder 取代 char[]:

  • LATIN-1 (ISO-8859-1) 字串:1 byte/字元,記憶體減半
  • UTF-16 字串:2 bytes/字元,相容既有行為
  • String、StringBuffer、StringBuilder 同步受益

七、常見反模式與修正

反模式問題修正
String s = ""; for(...) s += x;O(n²) 物件分配StringBuilder sb = new StringBuilder(); for(...) sb.append(x);
log.debug("msg=" + obj.toString())日誌級別關閉時仍執行拼接log.debug("msg={}", obj) // SLF4J 延遲評估
StringBuilder 作為欄位共享執行緒不安全ThreadLocal<StringBuilder> 或方法區域變數
new StringBuilder(1000000)過度預分配造成記憶體浪費合理預估或分批處理

八、總結

  1. String:不可變、執行緒安全、適合常量、金鑰、少量拼接
  2. StringBuffer:舊版遺產、同步開銷大、**幾乎不再推薦新代碼使用**
  3. StringBuilder:現代首選、單執行緒高效能、配合容量預估效能最強
  4. + 號:單行多拼接放心用、迴圈/多行嚴禁
  5. JDK 9+:Compact Strings 讓所有字串操作自動省記憶體

理解底層機制,才能寫出既優雅又高效的 Java 字串處理代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved