Java 字符串 split 的一个反直觉陷阱

news2025/1/20 10:48:18

最近生产环境遇到一个奇怪的数组下标越界报错,如下图代码所示,我们可以肯定的是 fieldName 变量不为空(不是空字符串,也不是 null),但是代码执行到读取 names[0] 变量的时候,抛出了一个 数组下标越界 (java.lang.ArrayIndexOutOfBoundsException) 的异常。

异常信息如下图所示

问题很简单,我们对一个字符串执行 split 方法之后,以过往其它编程语言(Go、PHP、Javascript、Dart 等)的使用经验来看,即使字符串为空,即使没有匹配到分隔符,在返回值数组中也会包含一个当前字符串的值。但是这里却抛出了 ArrayIndexOutOfBoundsException,难道 split 方法的返回值可能为空数组?

最终经过排查发现,在上述代码段中,当 fieldName 的值为 "~" 的时候,我们访问 names[0] 就会抛出 ArrayIndexOutOfBoundsException,为什么会这样呢?

本文将会持续修正和更新,最新内容请参考我的 GITHUB 上的 程序猿成长计划 项目,欢迎 Star,更多精彩内容请 follow me。

问题
在 Java 中,如果执行下面这段代码,直觉上你认为会输出什么?

String str = "~";
String []arr = str.split("~");

System.out.println(arr.length);

 

如果你有其他编程语言的经验,可能直觉上会觉得这里输出的应该是 2,但是遗憾的是,这里输出的是 0,变量 arr 是个空数组。

这里不禁怀疑自己之前的记忆是不是有偏差,于是我又使用其它语言来尝试复现这个问题。

不同语言中 split 的行为
我总结了一个表格,说明了不用语言不同的行为,这里对比的是执行 split 函数 / 方法后返回数组的长度:

 

Javascript

首先是 Javascript,在浏览器的控制台上直接执行,得到了下面的结果

"".split("")
"~".split("~")
"~~".split("~")
"".split("~")
"~123".split("~")

跟我的直觉是一致的,同样的情况,这里返回的是 2

PHP

在 PHP 中,我使用了 mb_split 函数,该函数用于对多字节字符串进行分割

执行结果如下

执行结果跟我的直觉也是一致的,同样的情况,这里返回的是 2

Dart

然后是 Google 的 Dart,这是一门主要用于使用 Flutter 来开发跨平台应用的编程语言,代码如下

void main() {
    print("".split('').length); // 0
    print("~".split('~').length); // 2
    print("~~".split('~').length); // 3
    print("".split('~').length); // 1
    print("~123".split('~').length); // 2
}

执行结果

同样,"~".split("~") 也是返回了两个值。

Golang

在 Golang 中,执行结果依旧是符合直觉的,返回的是 2

package main

import(
    "strings"
    "fmt"
)

func main() {
    printStrs(strings.Split("", "")) // 0 []
    printStrs(strings.Split("~", "~")) // 2 ["", "", ]
    printStrs(strings.Split("~~", "~")) // 3 ["", "", "", ]
    printStrs(strings.Split("", "~")) // 1 ["", ]
    printStrs(strings.Split("~123", "~")) // 2 ["", "123", ]
}

func printStrs(s []string) {
    fmt.Print(len(s), " [")
    for _, item := range s {
        fmt.Printf(`"%s", `, item)
    }

    fmt.Print("]\n")
}

 

执行结果

Scala
然后,我又尝试了 Scala,发现在 Scala 中, split 的行为有些不一样了。

"".split("").length
"~".split("~").length
"~~".split("~").length
"".split("~").length
"~123".split("~").length


代码 "~".split("~") 返回的是 空数组,与在 Java 中我们遇到的问题如出一辙。

Java
最后,我又用 Java 执行了同样的代码

package example;
import org.junit.Test;

public class ExampleTest {
  @Test
  public void testSplit() {
    printStrings("".split("")); // 1 ["", ]
    printStrings("~".split("~")); // 0 []
    printStrings("~~".split("~")); // 0 []
    printStrings("".split("~")); // 1 ["", ]
    printStrings("~123".split("~")); // 2 ["", "123", ]
  }

  private void printStrings(String[] strings) {
    System.out.print(strings.length + " [");
    for (String str : strings) {
      System.out.printf("\"%s\", ", str);
    }
    System.out.println("]");
  }
}


执行结果

结果与 Scala 是一致的,同时也解释了为什么我们会遇到 ArrayIndexOutOfBoundsException 的问题。

原因
翻阅了 Java 的 API 文档,发现原来 Java 中的 split 方法确实跟其它语言是不一样的,这一点我们特别容易忽略

如果分隔符表达式与字符串不匹配,则返回原始字符串作为数组的唯一值,这也就解释了

"".split("") // 1 [""]
"".split("~") // 1 [""]


如果分隔符表单式与字符串的开始字符就已经匹配了,则返回值中第一个元素会被设置为 ""

"~123".split("~") // 2 ["", "123"]


如果 limit 参数为 0,也就是 split(String regex) 方法,则匹配结果末尾的所有空字符串 "" 都会被丢弃,也就解释了下面两段代码

"~".split("~") // 0 []
"~~".split("~") // 0 []


然后我又翻阅了 Scala 的官方文档,Scala 和 Java 的行为是一致的。

总结
在 Java 中使用字符串的 split 方法,一般情况下的行为是和其他编程语言是一致的,但在一些边界条件下,也有一些不一致的地方,这一点是我们应该注意的,这也提醒了我们,不要想当然的认为不同语言,同名函数(方法)的功能是完全一致的,当我们遇到一些奇奇怪怪的问题时,多看官方文档才是硬道理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/84627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5G无线技术基础自学系列 | 抗衰落技术

素材来源:《5G无线网络规划与优化》 一边学习一边整理内容,并与大家分享,侵权即删,谢谢支持! 附上汇总贴:5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 无线信道是随机时变信道,信…

【云计算与大数据技术】文件存储格式行式、列式、GFS、HDFS的讲解(图文解释 超详细)

一、分布式文件系统 文件系统最后都需要以一定的格式存储数据文件,常见的文件存储布局有行式存储、列式存储以及混合式存储三种,不同的类别各有其优缺点和适用的场景,在目前的大数据分析系统中,列式存储和混合式存储方案因其特殊…

mysql 数据库设计三大范式

1. 什么是设计范式 设计表的依据,按照范式设计出来的表,不会出现数据的冗余 数据库的设计范式是数据库设计所需要满足的规范,满足这些规范的数据库是简洁的、结构清晰的;反之则是乱七八糟,不仅会给开发人员制造麻烦&a…

大数据面试之Hive常见题目

大数据面试之Hive常见题目 1. Hive的架构 1、重点四个器:解释器(SQL Parser)、Driver:编译器(Compiler),优化器(Optimizer),执行器(Executor&…

基于Python+Django的在线学习交流平台

在各学校的教学过程中,直播授课管理是一项非常重要的事情。随着计算机多媒体技术的发展和网络的普及,“基于网络的学习模式”正悄无声息的改变着传统的直播学习模式,“基于网络的直播教学平台”的研究和设计也成为教育技术领域的热点课题。采…

BEPUphysicsint定点数3D物理引擎介绍

帧同步的游戏中如果用物理引擎,为了保证不同设备上的结果一致,需要采用定点数来计算迭代游戏过程中的物理运算。也就是我们通常说的定点数物理引擎(确定性物理引擎)。本系列教程给大家详细的讲解如何在你的项目中内置一个确定性物理引擎。确定性物理引擎我们使用git…

es入门(中)

目录 6.Java api 实现es中的文档管理(增删改) 6.1 java 客户端简单获取数据 6.2结合spring-boot测试文档查询 配置环境 配置类 测试代码结构 简单的查询 对查询的请求设置参数 异步查询 6.4 结合spring-boot测试文档新增 6.5结合spring-boot…

C语言的预处理器无法先展开宏再拼接符号?可以!

背景 最近接到一个需求,要实现一个脚本,能提取.h文件里定义的所有全局变量的值,这些全局变量都是结构体变量,名字是结构体类型名加场景后缀——每个.h对应的场景都是唯一的,所以.h内所有变量名的后缀一致。 我的解决…

线段树详解(包含加法线段树、乘法线段树及区间根号线段树,简单易懂)

同步发表于洛谷梦回江南 这一篇文章我们将对线段树中的常规操作进行详细的讨论。 以下所提到的复杂度如无特殊说明均为时间复杂度。log⁡\loglog 的底数均为 222。 不开 long long 见祖宗! 文章目录第一部 普通线段树一、引入二、优化方案三、懒标记(l…

[附源码]Python计算机毕业设计电影网站系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

什么是编程的设计模式,史上最全面Java设计模式总结,看完再也不会忘记

文章目录**9.1 工厂方法模式与抽象工厂模式对比#****9.2 简单工厂模式与单例模式对比#****9.3 简单工厂模式与建造者模式对比#****10.1 装饰器模式与代理模式对比#****10.2 装饰器模式与门面模式对比#****10.3 装饰器模式与适配器模式对比#****10.4 适配器模式与代理模式…

人事管理系统--低代码课程的教学实验/实训教学 (①招聘管理)

人事管理系统是信息系统课程中最为常见的教学场景,对于非计算机专业的学生来说,如何使用低代码,甚至是零代码的方式搭建该系统呢?简道云「人事OA管理」应用包含招聘管理、人员入离职管理、考勤管理、会议室预约、物资进销存管理等…

#3文献学习总结--边缘计算资源分配与任务调度优化

文献:“边缘计算资源分配与任务调度优化综述 ” 1、系统模型“云-边-端” 第 1 层是物联网层,传感器、处理器根据应用需求感知、测量和收集原始数据,在本地处理大量数据或将其上传至计算节点。 第 2 层是边缘计算层,位于互联网边…

rollup打包vue组件

rollup安装与使用 npm i rollup -g # 全局安装 npm i rollup -D # 项目本地安装rollup配置 import vue from rollup-plugin-vue import typescript from rollup-plugin-typescript2 import postcss from rollup-plugin-postcss; import cssnano from cssnano i…

2022华为全球校园AI算法精英赛:季军方案!

Datawhale干货 作者:鲤鱼,西安交通大学,人工智能学院笔者鲤鱼,是西安交通大学人工智能学院的一名研究生,在2022华为全球校园AI算法精英赛的赛道二取得了季军的成绩。初赛阶段一直名列A榜的榜首,复赛前几天也…

zabbix6.0安装教程(二):Zabbix6.0安装最佳实践

zabbix6.0安装教程(二):Zabbix6.0安装最佳实践 目录概述一、Access control1.Zabbix agent 的安全用户2.UTF-8 编码二、Zabbix Security Advisories and CVE database1.为 Zabbix 前端设置 SSL三、Web server hardening1.在 URL 的根目录上启…

[附源码]Python计算机毕业设计SSM基于的开放式实验室预约系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

人家这才叫软件测试工程师,你那只是混口饭吃

前些天和大学室友小聚了一下,喝酒喝大发了,谈天谈地谈人生理想,也谈到了我们各自的发展,感触颇多。曾经找工作我迷茫过、徘徊不,毕业那会我屡屡面试失败,处处碰壁;工作两年后我一度想要升职加薪…

[附源码]Python计算机毕业设计SSM基于的二手车商城(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

第五款!美创数据水印溯源系统通过中国信通院数据安全能力评测

近期,中国信息通信研究院安全研究所发布“数据安全产品能力验证计划”第六期通过企业名单。美创科技数据水印溯源系统顺利通过测试,成为美创第五款通过权威检验测评的数据安全产品! 此前,中国信息通信研究院安全所开展数据安全类产…