关于Split我们都知道是用于切割字符串的,最近一朋友问我如果两个字符之间有两个空格,那通过一个空格去切会切成一个多大的数组,我几乎毫不犹豫的说两个,我的想法是这样的,当我们把所有空格都"切"出来,当遇到连续两个空格的时候,因为两个空格切去后中间是没有任何字符串的,我就臆想着Java肯定就会做相关的优化把"两个空格中的空字符串"去掉(之后发现并没有这样的处理),然后,嗯...就切成两个╮(-_-)╭
然而现实却把我啪啪的打了一顿,先上一个我写的小Demo
运行之后的结果,居然是
跟我预想的有点不一样。感觉他的切和我想象中的切有很大的区别,然后我只能跑去看了波源码,看看Split到底是如何实现切割的,首先上面写的小Demo中的Split方法首先是调用
这里是进行了方法重载,接着调用:
这个方法有两个参数一个String用于匹配要切的字段,另一个int类型的limit是要切成的数组的大小
初始化一个char类型变量ch,主要用于if条件中的判断使用主要是让所切字段是一个字符的情况进行处理,其他的转到正则中进行切割,转正则在这里就不讨论了!首先对if中的条件进行整理,因为就这样看有点头晕:
(
(regex.value.length == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)
((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&((ch-'a')|('z'-ch)) < 0 &&((ch-'A')|('Z'-ch)) < 0))
)&&
(
ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE
)
好了,大概就是这样一个结构!
红色部分就是限定当传入的String长度是1的时候,而且这个字符不能是 . $ | ( ) [ { ^ ? * + \ 中的一个
不是0-9 a-z A-Z
不是一个UTF-16(\uD800-\uDFFF)范围的字符都可以(具体原因:UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却无法兼容于ASCII编码。)
if块内首先初始化三个标志 off标志返回数组元素的切割过程中的起始点 next标志着下一个匹配要切字段的索引 limited标志是不是要返回固定的数组大小(根据limit判断)然后定义一个有序数组集合;当有匹配就进入while循环,并且把next重新赋上第一个匹配上字符的索引!
所以上面Demo中,两个空格导致的最终是进行了一个substring(第一个空格+1,第二个空格),两个参数相等,返回空串)接下来继续循环;如果if语句中判断差一个(limit-1)到要求长度,就到else中把接下来所有的字段保存在最后一个list中!
当在while中循环完成后,首先没指定固定长度的和字段完全按照传入参数进行切割的数组大小小与要求返回大小(limit)的情况没有进入else中进行结尾操作,所以后面进行了一步结尾操作
if (!limited || list.size() < limit)
list.add(substring(off, value.length));
还有在while条件中没有一个匹配情况下直接放回原数组
if (off == 0)
return new String[]{this};
然后就对结尾的空格进行去除(并没有对中间的元素为空的进行去除,我想多了。。。)转数组 返回,大概就是这样
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--;
}
}
String[] result = new String[resultSize]; return list.subList(0, resultSize).toArray(result);
所以,由此可得,当两个空格然后用空格去切的时候,是会切出一个空串的(substring两个参数相同就返回空串),当然前提是不再最后,因为最后的空串会被去除,像如果被切字符串是##,用#去切,最终数组长度为0。