【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站均有视频解说,欢迎来玩。

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

相关文章
|
22天前
|
存储 安全 Java
Java零基础-字符串详解
【10月更文挑战第18天】Java零基础教学篇,手把手实践教学!
97 60
|
12天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
35 6
|
15天前
|
JSON 前端开发 JavaScript
java-ajax技术详解!!!
本文介绍了Ajax技术及其工作原理,包括其核心XMLHttpRequest对象的属性和方法。Ajax通过异步通信技术,实现在不重新加载整个页面的情况下更新部分网页内容。文章还详细描述了使用原生JavaScript实现Ajax的基本步骤,以及利用jQuery简化Ajax操作的方法。最后,介绍了JSON作为轻量级数据交换格式在Ajax应用中的使用,包括Java中JSON与对象的相互转换。
31 1
|
22天前
|
SQL 监控 Java
技术前沿:Java连接池技术的最新发展与应用
本文探讨了Java连接池技术的最新发展与应用,包括高性能与低延迟、智能化管理和监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,为开发者提供了一份详尽的技术指南。
29 7
|
24天前
|
移动开发 前端开发 Java
过时的Java技术盘点:避免在这些领域浪费时间
【10月更文挑战第14天】 在快速发展的Java生态系统中,新技术层出不穷,而一些旧技术则逐渐被淘汰。对于Java开发者来说,了解哪些技术已经过时是至关重要的,这可以帮助他们避免在这些领域浪费时间,并将精力集中在更有前景的技术上。本文将盘点一些已经或即将被淘汰的Java技术,为开发者提供指导。
50 7
|
20天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
34 3
|
20天前
|
SQL 监控 Java
Java连接池技术的最新发展,包括高性能与低延迟、智能化管理与监控、扩展性与兼容性等方面
本文探讨了Java连接池技术的最新发展,包括高性能与低延迟、智能化管理与监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,以实现高效稳定的数据库访问。示例代码展示了如何使用HikariCP连接池。
12 2
|
22天前
|
Java 数据库连接 数据库
优化之路:Java连接池技术助力数据库性能飞跃
在Java应用开发中,数据库操作常成为性能瓶颈。频繁的数据库连接建立和断开增加了系统开销,导致性能下降。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接,显著减少连接开销,提升系统性能。文章详细介绍了连接池的优势、选择标准、使用方法及优化策略,帮助开发者实现数据库性能的飞跃。
27 4
|
20天前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
20 1
|
20天前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
32 1