String 不可變性:所有操作返回新對象
String s = "abc"; s.replace('a', 'x'); // s 仍為 "abc",需接收返回值
一、構造與轉換
| 操作 | 方法 | 範例 |
| 字元陣列 → String | new String(char[])
new String(char[], offset, count)
String.valueOf(char[])
String.copyValueOf(char[]) | char[] cs = {'J','a','v','a'}; String s = new String(cs, 1, 2); // "av" |
| String → 字元陣列 | toCharArray() | "Java".toCharArray() // ['J','a','v','a'] |
| 位元組陣列 → String | new String(byte[])
new String(byte[], offset, length, charset) | new String(bytes, StandardCharsets.UTF_8) |
| String → 位元組陣列 | getBytes(charset) | "中文".getBytes(StandardCharsets.UTF_8) |
| 基本型別 → String | String.valueOf(int/double/boolean...) | String.valueOf(123) // "123" |
二、查找與索引
| 方法 | 說明 | 返回值 |
charAt(int index) | 指定索引字元 | char |
indexOf(int ch) | 字元首次出現位置 | int (-1 表未找到) |
indexOf(String str) | 子串首次出現位置 | int |
indexOf(String str, int fromIndex) | 從指定位置搜尋 | int |
lastIndexOf(String str) | 子串最後出現位置 | int |
lastIndexOf(String str, int fromIndex) | 從指定位置反向搜尋 | int |
三、判斷與檢查
| 方法 | 說明 | 版本 |
contains(CharSequence s) | 是否包含子序列 | 1.5+ |
isEmpty() | 長度為 0 | 1.6+ |
isBlank() | 空或僅含空白字元 | 11+ |
startsWith(String prefix) | 是否以指定前綴開頭 | |
endsWith(String suffix) | 是否以指定後綴結尾 | |
equals(Object obj) | 內容相等(區分大小寫) | |
equalsIgnoreCase(String str) | 忽略大小寫比較 | |
matches(String regex) | 整體匹配正則 | |
四、子串擷取
String s = "abcdef";
// 從索引 2 到結尾
s.substring(2); // "cdef"
// 索引 2 到 4(不含 4)
s.substring(2, 4); // "cd"
// 等價於 substring(0, end)
s.substring(0, 3); // "abc"
// 注意:Java 7u6 前 substring 共用底層 char[],大字串切片可能洩漏
// 現代 JDK 已複製,但保險起見:new String(s.substring(...))
五、切割
String csv = "a,b,c,,,";
// 簡單切割(尾部空串丟棄)
csv.split(","); // ["a", "b", "c"]
// 保留尾部空串
csv.split(",", -1); // ["a", "b", "c", "", "", ""]
// 限制結果長度
csv.split(",", 3); // ["a", "b", "c,,,"]
// 正則切割
"a1b2c3".split("\\d+"); // ["a", "b", "c"]
六、替換
| 方法 | 說明 | 範例 |
replace(char old, char new) | 字元替換(全部) | "java".replace('a','o') // "jovo" |
replace(CharSequence old, CharSequence new) | 字串替換(全部,非正則) | "java".replace("va","ython") // "jython" |
replaceAll(String regex, String replacement) | 正則替換(全部) | "a1b2".replaceAll("\\d", "#") // "a#b#" |
replaceFirst(String regex, String replacement) | 正則替換(首個) | "a1b2".replaceFirst("\\d", "#") // "a#b2" |
七、大小寫、去空格、比較
| 方法 | 說明 | 注意 |
toUpperCase() | 轉大寫 | Locale 敏感,建議 toUpperCase(Locale.ROOT) |
toLowerCase() | 轉小寫 | 同上 |
trim() | 移除首尾 ≤ U+0020 字元 | 含空格、製表、換行 |
strip() | 移除首尾 Unicode 空白 | 11+,更完整 |
stripLeading/trailing() | 單側去空白 | 11+ |
compareTo(String s) | 字典序比較 | 實現 Comparable,可用於排序 |
compareToIgnoreCase(String s) | 忽略大小寫比較 | |
format(String fmt, Object... args) | 靜態格式化 | String.format("%04d", 42) // "0042" |
八、實戰綜合案例:解析鍵值對字串
public class StringParsingDemo {
public static Map parseKeyValue(String input, String pairDelim, String kvDelim) {
Map map = new LinkedHashMap<>();
if (input == null || input.isBlank()) return map;
// 1. 切割鍵值對
String[] pairs = input.split(pairDelim);
for (String pair : pairs) {
// 2. 切割鍵值
String[] kv = pair.split(kvDelim, 2); // 限制 2 段,值中可含分隔符
if (kv.length == 2) {
String key = kv[0].strip();
String value = kv[1].strip();
if (!key.isEmpty()) map.put(key, value);
}
}
return map;
}
public static void main(String[] args) {
String data = " user=admin ; role=super_admin ; status=active ";
Map parsed = parseKeyValue(data, ";", "=");
System.out.println(parsed); // {user=admin, role=super_admin, status=active}
}
}
九、效能最佳實踐
- 頻繁拼接用 StringBuilder:
new StringBuilder().append(a).append(b).toString()
- 正則複用 Pattern:
static final Pattern P = Pattern.compile(regex); P.matcher(input).matches()
- 大量切割考慮手寫解析:避免正則開銷
- 比較優先用 equals:
== 僅比較引用,極易出錯
- 格式化用 String.format:可讀性優於拼接
總結
String 方法族繁多,核心在於掌握不可變性、編碼轉換、正則與普通方法區別、Java 11+ 新增 strip/isBlank 等 Unicode 感知方法。實務中善用 StringBuilder、Pattern、String.format,避開 substring 記憶體洩漏(舊版本)、== 比較內容等經典坑。