元数据卡
- 前置知识:字符串基础(上一页)
- 预计时间:15 分钟
- 完成标志:能正确分割、替换字符串,知道什么场景用 StringBuilder
你的进度
你知道 String 不可变了。那日常怎么拆字符串、拼字符串、替换文本?遇到大量拼接时,为什么必须扔掉 + 号换成 StringBuilder?这一页不问了,直接上手。
substring —— 截取子串
java
String url = "https://example.com/api/users";
String domain = url.substring(8, 23); // [8, 23)
String path = url.substring(23);
System.out.println(domain);
System.out.println(path);运行步骤: 索引从 0 数:h(0) t(1) ... e(8) ... substring(8, 23) 取含 8 不含 23 的字符。
预期输出:
example.com
/api/userssplit —— 分割字符串(经典坑)
java
String ip = "192.168.1.1";
String[] parts = ip.split("."); // 参数是正则!
System.out.println(Arrays.toString(parts));
String[] parts2 = ip.split("\\."); // 正确写法
System.out.println(Arrays.toString(parts2));运行步骤: "." 在正则里匹配任意字符(不是字面点号),整个串被匹配光,返回空数组。
预期输出:
[]
[192, 168, 1, 1]面试高频题,也是线上出 Bug 最多的 split 坑。记住:特殊字符要转义。
trim 和 strip —— 去除空白
java
String padded = " \u2003Hello\u2003 "; // \u2003 是全角空格
System.out.println("'" + padded.trim() + "'");
System.out.println("'" + padded.strip() + "'"); // Java 11+预期输出:
' Hello ' (trim 没去干净)
'Hello' (strip 去了)Java 11 以上优先用 strip()。
replace 和 replaceAll
java
String text = "I like cats. Cats are cute.";
String r1 = text.replace("cats", "dogs"); // 字面量替换
String r2 = text.replaceAll("\\b[Cc]ats\\b", "dogs"); // 正则替换
System.out.println(r1);
System.out.println(r2);预期输出:
I like dogs. Cats are cute.
I like dogs. dogs are cute.replace() 是字面量,replaceAll / replaceFirst 是正则。
StringBuilder vs StringBuffer
java
// 循环用 += 拼接 —— 每次等价于 new StringBuilder().append()...toString()
String result = "";
for (int i = 0; i < 100_000; i++) {
result += "line " + i + "\n";
}
// 10 万次 = 10 万个临时对象,GC 暴走
// 正确做法
StringBuilder sb = new StringBuilder(1_000_000); // 预分配容量
for (int i = 0; i < 100_000; i++) {
sb.append("line ").append(i).append("\n");
}
String result2 = sb.toString();| 特性 | StringBuilder | StringBuffer |
|---|---|---|
| 线程安全 | 不安全 | 同步 |
| 性能 | 最快 | 慢 2-3 倍 |
| 适用 | 单线程拼接(99% 场景) | 多线程共享缓冲区 |
选择原则:除非明确多线程共享,永远用 StringBuilder。
常用方法速查
| 方法 | 作用 | 注意 |
|---|---|---|
| length() | 字符串长度 | 不是属性,是方法 |
| charAt(i) | 取第 i 个字符 | 越界抛异常 |
| substring(b, e) | 截取 | 终点不含 |
| indexOf(ch) | 查找位置 | -1 找不到 |
| contains(s) | 是否含子串 | 内部调 indexOf |
| split(regex) | 按正则分割 | 参数是正则 |
| replace(a, b) | 字面替换 | 不是正则 |
| replaceAll(re, s) | 正则替换全部 | 参数是正则 |
| trim() | 去 ASCII 空格 | 不处理 Unicode |
| strip() | 去所有空白 | Java 11+ 推荐 |
| join(delim, parts) | 合并 | 静态方法 |
java
String[] fruits = {"apple", "banana", "orange"};
String joined = String.join(", ", fruits);
System.out.println(joined);预期输出:
apple, banana, orangejava
String result = " Hello World ".strip().substring(0, 5).toUpperCase();
System.out.println(result);运行步骤: strip → "Hello World" → substring(0, 5) → "Hello" → toUpperCase → "HELLO"
预期输出:
HELLO旅人笔记
split 的参数是正则,特殊字符要转义。大量拼接用 StringBuilder + 预分配容量。strip() 比 trim() 更彻底。replace 是字面量,replaceAll 是正则。
-> 下一步:核心集合
字符串搞定了。但要存几十个"hello"、按名字查人、保证不重复——你需要集合框架了。