一切都按计划进行,但让我们一步一步来(希望你有时间)。
根据documentation(和source code)的split(String regex)方法:
此方法的工作原理就像通过使用给定表达式和零限制参数调用双参数拆分方法一样。
所以当你调用
split(String regex)
您实际上是从split(String regex, int limit) 方法获得结果,该方法以某种方式调用:
split(regex, 0)
所以这里limit 设置为0。
关于这个参数你需要知道几点:
- 如果
limit 为正数,则您将结果数组的长度限制为您指定的正数,因此"axaxaxaxa".split("x",2) 将返回一个数组["a", "axaxaxa"],而不是["a","a","a","a","a"]。
-
如果limit 是0,那么您没有限制结果数组的长度。但这也意味着任何尾随的空字符串都将被删除。例如:
"fooXbarX".split("X")
将在开始时生成一个如下所示的数组:
["foo", "bar", ""]
("barX" 在"X" 上拆分生成"bar" 和""),但由于split 删除了所有尾随空字符串,它会返回
["foo", "bar"]
-
limit 的负值行为类似于将limit 设置为0 的行为(它不会限制结果数组的长度)。唯一的区别是它不会从结果数组的末尾删除空字符串。换句话说
"fooXbarX".split("X",-1)
将返回["foo", "bar", ""]
让我们来看看案例,
",".split(",").length
which(如前所述)与
相同
",".split(",", 0).length
这意味着我们使用的 split 版本不会限制结果数组的长度,但会删除所有尾随的空字符串,""。您需要了解,当我们拆分 一个 东西时,我们总是得到 两个 东西。
换句话说,如果我们拆分"abc" 代替b,我们将得到"a" 和"c"。
棘手的部分是要理解,如果我们将"abc" 拆分为c,我们将得到"ab" 和""(空字符串)。
使用这个逻辑,如果我们将"," 拆分为,,我们将得到"" 和""(两个空字符串)。
您可以使用带有负数限制的split 进行检查:
for (String s: ",".split(",", -1)){
System.out.println("\""+s+"\"");
}
将打印出来
""
""
所以我们在这里看到的结果数组最初是["", ""]。
但由于默认情况下我们使用 limit 设置为 0,所有尾随的空字符串都将被删除。在这种情况下,结果数组只包含尾随的空字符串,因此所有这些都将被删除,留下空数组[],其长度为0。
回答这个问题
"".split(",").length
您需要了解仅当此类尾随空字符串是拆分结果(并且很可能不需要)时,删除尾随空字符串才有意义。
因此,如果没有我们可以拆分的任何地方,就不可能创建空字符串,因此运行这个“清理”过程是没有意义的。
此信息在documentation of split(String regex, int limit)方法中提及,您可以阅读:
如果表达式不匹配输入的任何部分,则结果数组只有一个元素,即这个字符串。
您还可以在 source code of this method(来自 Java 8)中看到这种行为:
2316 public String[] split(String regex, int limit) {
2317 /* 快速路径,如果 regex 是a
2318 (1)one-char 字符串,并且此字符不是
2319 RegEx 的元字符“.$|()[{^?*+\\”之一,或
2320 (2)双字符字符串,第一个字符是反斜杠
2321 第二个不是 ascii 数字或 ascii 字母。
2322 */
2323 char ch = 0;
2324 if (((regex.value.length == 1 &&
2325 ".$|() [{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
2326 (regex.length() == 2 &&
2327 regex.charAt(0) == '\\' &&
2328 (((ch = regex.charAt(1))-'0')|('9 '-ch)) 2329 ((ch-'a')|('z'-ch)) 2330 ((ch-'A')|( 'Z'-c h)) 2331 (ch 2332 ch > Character.MAX_LOW_SURROGATE))
2333 {
2334 int off = 0;
2335 int next = 0;
2336 boolean limited = limit > 0;
2337ArrayListString> list = new ArrayList();
2338 while ((next = @987654358 @(ch, off)) != -1) {
2339 if (!limited || list.size() 2340 list.add(substring(off, next));
2341 off = next + 1;
2342 } else { // 最后一个
2343 //assert (list.size() == limit - 1);
2344 list.add (substring(off, value.length));
2345 off = value.length;
2346 break;
2347 }
2348 }
2349 // 如果没有找到匹配项,返回这个
2350 if (off == 0)
2351 return new String[]{this};
2353 // 添加剩余段
2354 if (!limited || list.size() 2355 list.add(substring(off, value.length));
2357 //构造结果
2358 int resultSize = list.size();
2359 if (limit == 0) {
2360 while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
2361resultSize--;
2362 }
2363 }
2364 String[] 结果 = 新 String[resultSize];
2365 返回 list.subList(0, resultSize).toArray(result);
2366 }
2367 return Pattern.compile(regex) .split(this, limit);
2368 }
在哪里可以找到
if (off == 0)
return new String[]{this};
片段表示
-
if (off == 0) - 如果off(从哪个方法开始搜索作为split 参数传递的正则表达式的下一个可能匹配项的位置)在遍历整个字符串后仍然是0,我们没有'找不到任何匹配项,所以字符串没有被拆分
-
return new String[]{this}; - 在这种情况下,我们只返回一个带有原始字符串的数组(由 this 表示)。
由于在"" 中甚至一次都找不到",",因此"".split(",") 必须返回一个包含一个元素的数组(您调用split 的空字符串)。这意味着这个数组的长度是1。
顺便说一句。 Java 8 引入了另一种机制。如果我们使用zero-length regex(如"" 或环视(?<!x))进行拆分,它会删除前导空字符串(如果它们是在拆分过程中创建的)。更多信息请访问:Why in Java 8 split sometimes removes empty strings at start of result array?