java.lang.String 是 Java 最基礎也最常用的類別,但其不可變特性與記憶體模型常被誤解,導致效能問題。本文系統整理 String 核心特性、關鍵方法、字串連接效能陷阱、StringBuffer/StringBuilder 選擇指南,以及 split/replaceAll 正則表達式陷阱與對策。
substring()、concat()、replace() 等方法均回傳新 String 物件,原物件不變。String s1 = "test"; // 字面常量,可能進入字串常量池
String s2 = new String("test"); // 強制在堆上建立新物件
| 方法 | 說明 |
|---|---|
equals(Object) | 內容比較 (區分大小寫) |
equalsIgnoreCase(String) | 內容比較 (忽略大小寫) |
length() | 字元總數 |
trim() | 移除首尾空白字元 (空格、\t、\n、\r) |
substring(int, int) / substring(int) | 擷取子字串 [start, end) / [start, 結尾) |
charAt(int) | 取得指定索引字元 |
indexOf(String) | 尋找子字串首次出現位置,找不到回傳 -1 |
concat(String) | 字串連接,等同 + 運算子 |
startsWith/endsWith(String) | 前綴/後綴判斷 |
String str = "I am " + "Lingo!"; 看似簡單,實際編譯後產生 三個 String 物件:兩個常量與一個連接結果。迴圈中連接字串會產生大量暫時物件,觸發頻繁 GC。
// 低效寫法
String result = "";
for (int i = 0; i < 10000; i++) result += "x"; // 產生 10000+ 個 String 物件
// 高效寫法:StringBuilder (單線程) / StringBuffer (多線程)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) sb.append("x");
String result = sb.toString(); // 僅 1 個 String 物件
// JVM 內部將 + 編譯為 StringBuilder.append (JDK 5+)
| 特性 | StringBuffer | StringBuilder |
|---|---|---|
| 線程安全 | 同步方法,線程安全 | 非同步,非線程安全 |
| 效能 | 較低 (鎖開銷) | 較高 (無鎖) |
| 適用場景 | 多線程共享字串緩衝區 | 單線程、區域變數、高效能需求 |
建議:除非確定需多線程共享,預設使用 StringBuilder。
reverse():反轉字串append(...):尾端追加 (支援多型別)insert(int, ...):指定位置插入delete(int, int):刪除區間內容兩者參數皆為 正則表達式 (regex),特殊字元需轉義。
"1,3,4".split(",") // 正確:["1", "3", "4"]
"1|3|4".split("|") // 錯誤:["1", "|", "3", "|", "4"] - "|" 在 regex 代表 "或"
"1|3|4".split("\\|") // 正確:["1", "3", "4"] - Java 字串需雙重轉義 \\ → \ → 字面 |
規則:regex 元字元 (| . * + ? ^ $ [ ] ( ) { } \) 作為字面字元時,需在 Java 字串中寫成 \\元字元。
str.replaceAll("\\|", ",") // 將所有 | 替換為 ,
StringBuilder;多線程共享用 StringBuffer。split/replaceAll 時務必掌握 regex 語法,特殊字元正確轉義 (\\)。substring 索引區間、trim 空白字元範圍。