【Java实用技术】字符串的拆分用什么方法好?有一半程序员都掉过split坑

简介: 【Java实用技术】字符串的拆分用什么方法好?有一半程序员都掉过split坑

必备字符串操作

我们将字符串操作分为下面6种:

  1. 基本操作方法
  2. 字符串判空、比较
  3. 字符串截取和拆分
  4. 字符串查找和替换
  5. 字符串和其他类型数据的转换
  6. 字符串拼接和格式化

今天我们来讲解第3.2节。


1、字符串拆分原生方法

对于字符串拆分的原生操作

//字符串拆分原生方法:publicString[] String.split(Stringregex)

问题:对字符串中含有“|”分割符部分进行拆分,怎么写?

直接str.split("|")可以吗?当然可以,但是结果是不是你想要的呢?

Stringstr="a.|b.";
***原生String.split方法结果*****[a, ., |, b, .]

答案:如果只是单纯想按照“|”分割,正确的写法是ss.split("\\|"),因为这里碰到烦人的正则表达式。

Stringstr="a.|b."; // 使用“|”拆分System.out.println("*** 原生 String.split 方法 *****");
if (StringUtils.isNotEmpty(str)) {
String[] s1=str.split("\\|");
System.out.println(Arrays.toString(s1));
}

split源码分析

// 选取源码中关键的分析/**围绕给定正则表达式的匹配拆分此字符串。此方法的工作方式就像通过使用给定表达式和零限制参数调用双参数split方法一样。 因此,结果数组中不包含尾随空字符串。参数:regex – 定界正则表达式返回:通过围绕给定正则表达式的匹配拆分此字符串计算出的字符串数组抛出:PatternSyntaxException – 如果正则表达式的语法无效*/publicString[] split(Stringregex) {
returnsplit(regex, 0);
}
/**围绕给定正则表达式的匹配拆分此字符串。以str形式调用此方法。 split(regex , n)产生与表达式相同的结果:Pattern.compile(regex).split(str , n)*/publicString[] split(Stringregex, intlimit) {
/* 下面情况使用快速模式:(1)单个字符但是不能是正则中的元字符,比如".$|()[{^?*+\\"(2)两个字符,第一个字符是\,第二个字符不能是数字或者字母[0-9a-zA-Z]*/charch=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))
        {
//省略 使用substring拆分  过程String[] result=newString[resultSize];
returnlist.subList(0, resultSize).toArray(result);
        }
// 其他场景使用正则表达式拆分returnPattern.compile(regex).split(this, limit);
    }


源码不复杂,核心内容是:

(1)不是正则表达式的元字符".$|()[{^?*+\\"\开头但后面不是[0-9a-zA-Z]的使用快速拆分模式

(2)其他情况使用正则表达式匹配模式拆分

这里涉及到另外一个知识点,正则表达式,如果对正则表达式感兴趣的可以参考其他博文。

当然我认为你是没有兴趣的,而且很多程序员也很讨厌正则表达的规则,需要用的时候再翻阅。

对于(1),如果你十分精通正则表达式,可以很快知道哪些是正则元字符,你可以尝试使用原生的方法,毕竟使用方便且拆分速度确实快。

对于(2),因为正则表达式需要编译再匹配,比较耗时,所以不建议使用正则表达式。至于为什么正则表达式会慢,你就想你只见过一个姑娘一面就想找到她,和你知道她的名字地址具体信息比,哪个找到她更快?

综上所述,原生方法存在以下问题:

  • 使用前要判空
  • 小心正则表达式里面特殊字符
  • 性能不佳

为什么不推荐StringTokenizer

当然有同学可能会说jdk还有一个用于拆分字符串的类:StringTokenizer,它不是基于正则表达式进行拆分,性能应该高。但是笔者并不推荐使用此方法进行字符串拆分。我们先看源码:

 

/**StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouragedin new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.Since: JDK1.0*/publicclassStringTokenizerimplementsEnumeration<Object> {
//...}


只看关键单词discouraged=不推荐。知道它是一个为了兼容而遗留下的类,官方不推荐使用就足够的。

另外一个不推荐的原因是:本来很简单的一个拆分,使用它需要搭配while循环,索性就不要用它了。


2、推荐字符串拆分操作

善用StringUtils.splitXX()

推荐使用Apache工具类StringUtils.splitXX()

优势:不用担心字符串为null(空),方法名直白。

推荐常用方法:

// 按照指定分割符拆分字符串publicstaticString[] split(Stringstr, Stringseparator)
// 按照完整分割符拆分字符串publicstaticString[] splitByWholeSeparator(Stringstr, Stringseparator)
// 拆分字符串,保留所有分割符位置 --较少使用publicstaticString[] splitPreserveAllTokens(Stringstr, StringseparatorChars)
// 获取分割符的前部分publicstaticString[] substringBefore(Stringstr, StringseparatorChars)
//获取分割符的后面部分publicstaticString[] substringAfterLast(Stringstr, StringseparatorChars)


对于上面问题按照“|”拆分,可以一行代码搞定。

Stringstr="a.|b.";
String[] s2=StringUtils.split(str, "|");
/* 输出:[a., b.] */

开发中比较常见的需求是对", . | * : "等进行拆分。如果你对正则元字符不熟悉,很容易写出错误的拆分。

所以还是建议直接使用StringUtils工具类进行拆分,减少写代码时的思考成本。

StringUtils.split也有坑


还是上述例子,如果对字符串"a.|b.c"按照".|"进行拆分,使用StringUtils.split可以吗?

// 问题:请使用“.|”拆分Stringstr="a.|b.c";
String[] s2=StringUtils.split(str, ".|");
/* 运行结果:[a, b, c]并不是期望的[a, b.c] */

答案是不行,拆分的结果是[a, b, c],并不是期望的[a, b.c], 这是因为StringUtils.split方法是将多字符分割符拆成单个分割符进行拆分,再将非分割符部分返回。

如果希望对多字符分割符拆分,请使用StringUtils.splitByWholeSeparator()方法。

这个小细节,希望大家能够避坑。


3、demo用例

importorg.apache.commons.lang3.StringUtils;
importjava.util.Arrays;
importjava.util.StringTokenizer;
/*** Java实用技术课程 By Pandas.* 公众号:Java实用技术手册* JDK版本:jdk1.8.0_66** @author Pandas* @date 2021/10/30*/publicclassStringSplitDemo {
/*** 字符串拆分方法用哪个方法好?*/publicstaticvoidmain(String[] args) {
// 问题:请使用“|”拆分Stringstr="a.|b.c";
System.out.println("*** 原生 String.split 方法 *****");
if (StringUtils.isNotEmpty(str)) {
String[] s1=str.split("\\|");
System.out.println(Arrays.toString(s1));
        }
String[] s11=StringUtils.split(str, "|");
System.out.println(Arrays.toString(s11));
System.out.println("*** 原生 StringTokenizer 方法 *****");
StringTokenizertokenizer=newStringTokenizer(str, "|");
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
        }
// "a.|b.c"str="a.|b.c";
System.out.println("*** StringUtils 方法 *****");
String[] s2=StringUtils.split(str, ".|");
System.out.println(Arrays.toString(s2));
String[] s3=StringUtils.splitByWholeSeparator(str, ".|");
System.out.println(Arrays.toString(s3));
str="a.|b...";
String[] s4=StringUtils.splitPreserveAllTokens(str, ".");
System.out.println(Arrays.toString(s4));
    }
}
/** 运行结果===>*** 原生 String.split 方法 *****[a., b.c][a., b.c]*** 原生 StringTokenizer 方法 *****a.b.c*** StringUtils 方法 *****[a, b, c][a, b.c][a, |b, , , ]*/


4、总结

  • 直接使用StringUtils最省事(注意上面写的避坑)。
  • 如果是对非特殊字符拆分,比如对字母数字拆分,可以使用原生的split方法。
  • 不要使用StringTokenizer。

感谢阅读本期内容,希望对新入行的你有帮助。

如果你意犹未尽,后面有一个字符串拆分姊妹篇,欢迎继续查看。


往期内容:


我是Pandas,专注Java编程实用技术分享,公众号Java实用技术手册和B站均有视频解说,欢迎来玩。

如果你觉得这篇文章有用,别忘了点赞+关注,一起进步!

相关文章
|
4天前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
14 1
|
22天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
76 4
|
23天前
|
JSON 前端开发 JavaScript
java-ajax技术详解!!!
本文介绍了Ajax技术及其工作原理,包括其核心XMLHttpRequest对象的属性和方法。Ajax通过异步通信技术,实现在不重新加载整个页面的情况下更新部分网页内容。文章还详细描述了使用原生JavaScript实现Ajax的基本步骤,以及利用jQuery简化Ajax操作的方法。最后,介绍了JSON作为轻量级数据交换格式在Ajax应用中的使用,包括Java中JSON与对象的相互转换。
38 1
|
26天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
72 2
|
28天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
44 3
|
28天前
|
SQL 监控 Java
Java连接池技术的最新发展,包括高性能与低延迟、智能化管理与监控、扩展性与兼容性等方面
本文探讨了Java连接池技术的最新发展,包括高性能与低延迟、智能化管理与监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,以实现高效稳定的数据库访问。示例代码展示了如何使用HikariCP连接池。
15 2
|
28天前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
27 1
|
28天前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
40 1
|
Java
JAVA方法的定义
JAVA方法的定义
89 0
|
6月前
|
安全 Java 编译器
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
43 1