Java 字符串split()方法的那些不为人知的坑

请问下列代码输出结果是什么?(文章结尾会告诉答案)


    private static final String REGEX = ";";

    public static void main(String[] args) throws Exception {
        split("");
        split(";");
        split(";", -1);
        split("1;;");
        split("1;;",-1);
        split("1;;1");
    }

    private static void split(String str) {
        split(str, 0);
    }

    private static void split(String str, int limit) {
        print(str.split(REGEX, limit), str);
    }

    private static void print(String[] arr, String str) {
        System.out.println(String.format("%s分隔后数组的长度=%s", str, arr.length));
        System.out.println(String.format("%s分隔后的数组内容为=%s", str, Arrays.toString(arr)));
        System.out.println("==================");
    }

要了解代码背后的原因,阅读源码是一种非常有效的方式。
String类的split()方法有两个重载的方法,这两个方法是

    public String[] split(String regex) {
        return split(regex, 0);
    }
    public String[] split(String regex, int limit) {
		// 一大推代码
	}

可以看到这个split()方法有两个参数,第一个参数是我们分隔的字符串的分隔符,第二个参数很奇怪哦,所以我们看一下源码是怎样解释的。
在这里插入图片描述
为了更好的说明上面英文的意思,我们以字符串"1;;1;",分隔为;为例。首先从我们意识里来说这段字符串可以被分隔成4段(分隔符的数量+1),也就是说n=4

limit数组长度说明
limit<04=n返回n长度的数组
limit=03<=n最后面的空字符串将被截取掉
0<limit<=nlimit<=n返回的数组长度等于limit
limit>n4=n返回的数组长度等于n

其中limit=0的情况就是默认情况public String[] split(String regex)。
接下来我们看一下源码部分:

public String[] split(String regex, int limit) {
	   	// 这里的意思是说对于简单的regex就在这里判断了 
        /* fastpath if the regex is a
         (1)one-char String and this character is not one of the
            RegEx's meta characters ".$|()[{^?*+\\", or
         (2)two-char String and the first char is the backslash and
            the second is not the ascii digit or ascii letter.
         */
        char ch = 0;
        if (((regex.value.length == 1 &&
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
             (regex.length() == 2 &&
              regex.charAt(0) == '\\' &&
              (((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))
        {
        // 截取代码部分
        }
        // 走正则表达式的部分,主要逻辑和截取代码部分相同
        return Pattern.compile(regex).split(this, limit);
}

下面我们重点关注截取部分的代码:
在这里插入图片描述
相信,至此你已经能够正确解答本文开头的例子了。

开头问题参考答案在这里插入图片描述

字符串处理利器Guava

最后补充一个goole公司开发的java工具包Guava,里面有一些非常实用的字符串处理工具。

    	<dependency>
           <groupId>com.google.guava</groupId>
           <artifactId>guava</artifactId>
           <version>28.1-jre</version>
       </dependency>

其中关于字符串的拆分的示例代码如下:

      // 拆分方式 忽略空的字符串 对截取的字符串做trim()
        List<String> split1 = Splitter.on(",").omitEmptyStrings().trimResults().splitToList("2,,3 ,4");
        List<String> split2 = Splitter.on(",").omitEmptyStrings().trimResults().splitToList("2,,3 ,4,,");
        List<String> split3 = Splitter.on(",").omitEmptyStrings().trimResults().splitToList("");
        System.out.println(String.format("长度=%s,内容=%s", split1.size(), split1));// 长度=3,内容=[2, 3, 4]
        System.out.println(String.format("长度=%s,内容=%s", split2.size(), split2));// 长度=3,内容=[2, 3, 4]
        System.out.println(String.format("长度=%s,内容=%s", split3.size(), split3));// 长度=0,内容=[]

关于Guava的更多实用方法可以参考 Guava用法总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值