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

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

相关文章
|
2月前
|
监控 Cloud Native Java
Quarkus 云原生Java框架技术详解与实践指南
本文档全面介绍 Quarkus 框架的核心概念、架构特性和实践应用。作为新一代的云原生 Java 框架,Quarkus 旨在为 OpenJDK HotSpot 和 GraalVM 量身定制,显著提升 Java 在容器化环境中的运行效率。本文将深入探讨其响应式编程模型、原生编译能力、扩展机制以及与微服务架构的深度集成,帮助开发者构建高效、轻量的云原生应用。
304 44
|
2月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
336 1
|
3月前
|
安全 Java 编译器
new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析
逃逸分析是一种静态程序分析技术,用于判断对象的可见性与生命周期。它帮助即时编译器优化内存使用、降低同步开销。根据对象是否逃逸出方法或线程,分析结果分为未逃逸、方法逃逸和线程逃逸三种。基于分析结果,编译器可进行同步锁消除、标量替换和栈上分配等优化,从而提升程序性能。尽管逃逸分析计算复杂度较高,但其在热点代码中的应用为Java虚拟机带来了显著的优化效果。
119 4
|
2月前
|
SQL JSON Java
告别字符串拼接:用Java文本块优雅处理多行字符串
告别字符串拼接:用Java文本块优雅处理多行字符串
347 108
|
3月前
|
Java API Maven
2025 Java 零基础到实战最新技术实操全攻略与学习指南
本教程涵盖Java从零基础到实战的全流程,基于2025年最新技术栈,包括JDK 21、IntelliJ IDEA 2025.1、Spring Boot 3.x、Maven 4及Docker容器化部署,帮助开发者快速掌握现代Java开发技能。
760 1
|
3月前
|
Java 测试技术 API
2025 年 Java 开发者必知的最新技术实操指南全览
本指南涵盖Java 21+核心实操,详解虚拟线程、Spring Boot 3.3+GraalVM、Jakarta EE 10+MicroProfile 6微服务开发,并提供现代Java开发最佳实践,助力开发者高效构建高性能应用。
575 4
|
2月前
|
安全 Cloud Native Java
Java 模块化系统(JPMS)技术详解与实践指南
本文档全面介绍 Java 平台模块系统(JPMS)的核心概念、架构设计和实践应用。作为 Java 9 引入的最重要特性之一,JPMS 为 Java 应用程序提供了强大的模块化支持,解决了长期存在的 JAR 地狱问题,并改善了应用的安全性和可维护性。本文将深入探讨模块声明、模块路径、访问控制、服务绑定等核心机制,帮助开发者构建更加健壮和可维护的 Java 应用。
239 0
|
3月前
|
JavaScript 安全 前端开发
Java开发:最新技术驱动的病人挂号系统实操指南与全流程操作技巧汇总
本文介绍基于Spring Boot 3.x、Vue 3等最新技术构建现代化病人挂号系统,涵盖技术选型、核心功能实现与部署方案,助力开发者快速搭建高效、安全的医疗挂号平台。
211 3
|
3月前
|
存储 人工智能 算法
Java 大视界 -- Java 大数据在智能医疗影像数据压缩与传输优化中的技术应用(227)
本文探讨 Java 大数据在智能医疗影像压缩与传输中的关键技术应用,分析其如何解决医疗影像数据存储、传输与压缩三大难题,并结合实际案例展示技术落地效果。
|
3月前
|
机器学习/深度学习 算法 Java
Java 大视界 -- Java 大数据在智能物流运输车辆智能调度与路径优化中的技术实现(218)
本文深入探讨了Java大数据技术在智能物流运输中车辆调度与路径优化的应用。通过遗传算法实现车辆资源的智能调度,结合实时路况数据和强化学习算法进行动态路径优化,有效提升了物流效率与客户满意度。以京东物流和顺丰速运的实际案例为支撑,展示了Java大数据在解决行业痛点问题中的强大能力,为物流行业的智能化转型提供了切实可行的技术方案。