split() 方法的基本用法
split() 方法用于根据给定的正则表达式(Regular Expression)将字符串拆分为一个字符串数组。

方法签名
public String[] split(String regex) public String[] split(String regex, int limit)
regex: 分割时使用的正则表达式,这是最关键也最容易出错的一点。limit: 分割的次数限制。
核心概念:regex 是正则表达式
这是 split() 方法最重要的特性,它的参数 regex 不是一个普通的字符串,而是一个正则表达式,这意味着很多在正则表达式中有特殊含义的字符,如果直接用作分隔符,会产生意想不到的结果。
常见的正则表达式元字符
| 字符 | 正则表达式中的含义 | 在 split() 中的影响 |
|---|---|---|
| 匹配任意单个字符 | "a.b".split(".") 会得到 ["a", "b"],而不是 ["a.b"] |
|
| “或”逻辑,表示匹配左右两边任意一个 | "a|b|c".split("|") 会得到 ["a", "|", "b", "|", "c"],而不是 ["a", "b", "c"] |
|
| 匹配前面的元素零次或多次 | "a*b".split("*") 会抛出 PatternSyntaxException |
|
| 匹配前面的元素一次或多次 | "a+b".split("+") 会抛出 PatternSyntaxException |
|
| 匹配前面的元素零次或一次 | "a?b".split("?") 会抛出 PatternSyntaxException |
|
^ |
匹配行的开头 | "^start".split("^") 会得到 ["", "start"] |
| 匹配行的结尾 | "end$".split("$") 会得到 ["end", ""] |
|
| 分组 | "(a)(b)".split("()") 会得到 ["", "a", "", "b", ""] |
|
\d |
匹配数字 | "a1b2c".split("\\d") 会得到 ["a", "b", "c"] |
\s |
匹配空白字符(空格, tab, 换行等) | "a b c".split("\\s") 会得到 ["a", "b", "c"] |
[] |
字符集,匹配其中的任意一个字符 | "a1b2c".split("[0-9]") 会得到 ["a", "b", "c"] |
如何处理特殊字符?
如果你想用上述某个特殊字符作为普通的分隔符,你需要对它进行转义,在 Java 字符串中,反斜杠 \ 本身也是一个特殊字符,它用来表示转义,要在字符串中表示一个字面上的反斜杠,你需要写成 \\。
示例:用点 分隔
String str = "192.168.1.1";
// 错误用法:. 在正则中是“任意字符”
String[] parts1 = str.split(".");
// 结果: ["192", "168", "1", "1"] (因为 . 匹配了每个字符之间的空隙)
// 正确用法:对 . 进行转义
String[] parts2 = str.split("\\.");
// 结果: ["192", "168", "1", "1"] (这才是我们想要的)
// 更推荐使用 Pattern.quote() 来自动处理
String[] parts3 = str.split(Pattern.quote("."));
// 结果: ["192", "168", "1", "1"]
Pattern.quote() 是一个非常好的工具,它会将任何字符串包装成一个字面意义的正则表达式,避免了手动转义的错误。

limit 参数详解
limit 参数决定了分割的次数上限。
limit > 0: 最多分割limit - 1次,数组的长度将不超过limit。limit < 0: 不限制分割次数,所有匹配都会被分割,这是默认行为。limit == 0: 不限制分割次数,但会丢弃末尾的空字符串。
limit 参数示例
String text = "a,b,c,,d"; // 注意中间有两个连续的逗号
// 1. limit < 0 (默认行为)
String[] parts1 = text.split(",");
// 结果: ["a", "b", "c", "", "d"] (保留了所有空字符串)
// 2. limit > 0
// 最多分割 2 次,得到 3 个部分
String[] parts2 = text.split(",", 3);
// 结果: ["a", "b", "c,,d"] (只分割了前两个逗号)
// 3. limit == 0
// 不限制次数,但会丢弃末尾的空字符串
String[] parts3 = text.split(",", 0);
// 结果: ["a", "b", "c", "", "d"] (在这个例子中,空字符串不在末尾,所以没被丢弃)
// 另一个例子,空字符串在末尾
String text2 = "a,b,c,";
String[] parts4 = text2.split(",", 0);
// 结果: ["a", "b", "c"] (末尾的空字符串被丢弃了)
高级用法与注意事项
1 处理连续的分隔符
默认情况下,split() 会保留由连续分隔符产生的空字符串。
String csv = "apple,orange,,banana";
String[] fruits = csv.split(",");
// 结果: ["apple", "orange", "", "banana"]
如果你希望忽略这些空字符串(CSV 中空单元格代表无效数据),你需要自己处理结果数组:
List<String> nonEmptyFruits = new ArrayList<>();
for (String fruit : fruits) {
if (!fruit.isEmpty()) {
nonEmptyFruits.add(fruit);
}
}
// nonEmptyFruits: ["apple", "orange", "banana"]
2 使用正则表达式进行复杂分割
split() 的真正威力在于它能使用复杂的正则表达式,按一个或多个空格分割:
String sentence = "This is a test.";
// 使用正则表达式 \s+ 表示一个或多个空白字符
String[] words = sentence.split("\\s+");
// 结果: ["This", "is", "a", "test."]
3 性能考虑
对于简单的、不需要正则表达式的分割场景,split() 可能不是最高效的选择,按固定字符分割。
String.split(): 每次调用都会编译一个新的正则表达式,如果在一个循环中频繁调用同一个模式的split(),性能会较差。StringTokenizer: 一个更老的类,专门用于分割字符串,它不使用正则表达式,性能通常更好,但功能较弱,且被认为是遗留代码。- 手动循环: 对于最简单的场景(如按单个字符分割),手动遍历字符串构建
List可能是最快的方法。
性能对比示例:
String data = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z";
// 高性能循环方式 (适合按单个字符分割)
List<String> result = new ArrayList<>();
int start = 0;
for (int i = 0; i < data.length(); i++) {
if (data.charAt(i) == ',') {
result.add(data.substring(start, i));
start = i + 1;
}
}
result.add(data.substring(start)); // 添加最后一个部分
// System.out.println(result);
最佳实践总结
split()使用正则表达式:这是最常见的错误来源。- 转义特殊字符:如果分隔符是 等特殊字符,务必使用
\\进行转义,或者更安全地使用Pattern.quote()。 - 处理空字符串:了解
split()默认会保留连续分隔符产生的空字符串,并根据业务需求决定是否需要过滤掉它们。 - 善用
limit参数:当你只想分割字符串的前几部分时,使用limit参数可以避免不必要的处理。 - 考虑性能:在性能敏感的代码中,如果只是简单的、非正则的分割,考虑手动循环或
StringTokenizer(尽管后者不推荐新代码使用)。 - 考虑替代方案:如果你的需求是解析像 CSV 或 JSON 这样的结构化数据,不要使用
split(),应该使用专门的库,如 OpenCSV, Jackson, Gson 等,它们能更正确、更安全地处理引号、转义字符等复杂情况。
代码示例汇总
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.regex.Pattern;
public class StringSplitExample {
public static void main(String[] args) {
// 1. 基本分割
String s1 = "apple,banana,cherry";
System.out.println("按逗号分割: " + Arrays.toString(s1.split(",")));
// 输出: [apple, banana, cherry]
// 2. 特殊字符分割
String s2 = "192.168.1.1";
// 错误: . 是任意字符
// System.out.println(Arrays.toString(s2.split(".")));
// 正确: 转义 .
System.out.println("按点分割(转义): " + Arrays.toString(s2.split("\\.")));
// 输出: [192, 168, 1, 1]
// 更好的方式
System.out.println("按点分割(Pattern.quote): " + Arrays.toString(s2.split(Pattern.quote("."))));
// 输出: [192, 168, 1, 1]
// 3. limit 参数
String s3 = "a,b,c,d,e";
System.out.println("limit=3: " + Arrays.toString(s3.split(",", 3)));
// 输出: [a, b, c,d,e]
String s4 = "a,b,,c"; // 包含连续逗号
System.out.println("默认(保留空字符串): " + Arrays.toString(s4.split(",")));
// 输出: [a, b, , c]
System.out.println("limit=0(丢弃末尾空串): " + Arrays.toString(s4.split(",", 0)));
// 输出: [a, b, , c] (空串不在末尾,所以保留)
String s5 = "a,b,c,";
System.out.println("limit=0(丢弃末尾空串): " + Arrays.toString(s5.split(",", 0)));
// 输出: [a, b, c] (空串在末尾,被丢弃)
// 4. 复杂正则分割
String s6 = "This is a test.";
System.out.println("按一个或多个空格分割: " + Arrays.toString(s6.split("\\s+")));
// 输出: [This, is, a, test.]
// 5. 过滤空字符串
String s7 = "apple,,orange,,,banana";
String[] parts = s7.split(",");
List<String> filteredList = new ArrayList<>();
for (String part : parts) {
if (!part.isEmpty()) {
filteredList.add(part);
}
}
System.out.println("过滤后的列表: " + filteredList);
// 输出: [apple, orange, banana]
}
} 