DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Java String.split(".") 返回空数组,读取第一个元素时报越界

String.split 的句点参数是正则通配符,配合默认移除尾部空字段会得到空数组。转义字面句点,再按字段契约决定是否保留末尾空值。

想按英文句点拆开字符串,结果数组长度却为零,接着访问下标 0 又抛出 ArrayIndexOutOfBoundsException:

String text = "alpha.beta.gamma";
String[] parts = text.split(".");
System.out.println(parts[0]);

应先检查分隔规则。String.split 的参数是正则表达式,英文句点在正则里并不表示普通句点。本文针对标准 Java 字符串 API;split 从 Java 1.4 提供,后文的 Pattern.quote 从 Java 5 提供。

任意字符匹配与尾部空字段一起造成空数组

在默认正则模式下,. 匹配除行终止符之外的任意字符。示例字符串没有换行,因此每个字符都被当作分隔符,切出来的片段全是空字符串。

单参数 split(regex) 又等同于 split(regex, 0),会丢弃尾部空字符串。这里所有片段都为空,最终长度就是零。若输入包含换行,结果可能不同,不能把“句点总会得到空数组”当成通用规则。

检查时先看数组长度与使用的正则,再看输入是否含行终止符。给数组访问加长度判断可以防止第二个异常,但并不会让错误的分隔规则变正确。

把句点作为字面量传入

固定使用英文句点分隔时,需要同时处理 Java 字符串和正则表达式两层转义:

import java.util.Arrays;

public class SplitExample {
    public static void main(String[] args) {
        String text = "alpha.beta.gamma";
        String[] parts = text.split("\\.");
        System.out.println(Arrays.toString(parts));
        // 预期 [alpha, beta, gamma]
    }
}

Java 源码中的 "\\." 传到正则引擎后是 \.,表示字面句点。不要写成 "\.",单个反斜杠加句点不是合法的 Java 字符串转义。

如果分隔符来自配置,并且配置表示普通文本,可以使用 Pattern.quote:

String delimiter = ".";
String[] parts = text.split(
    java.util.regex.Pattern.quote(delimiter)
);

这个片段沿用前面的 text。如果配置本来允许填写正则,就不能统一加 quote,否则会改变配置含义。

需要保留末尾空字段时,再设置 limit

修正句点后,末尾空字段是否保留仍由接口约定决定:

String text = "alpha.beta.";
String[] dropped = text.split("\\.");
String[] kept = text.split("\\.", -1);
// dropped 预期为两个元素:alpha、beta
// kept 预期为三个元素:alpha、beta、空字符串

负数 limit 保留尾部空字符串;正数则限制结果数量,最后一个元素保留剩余内容。只给错误的 split(".") 加上 -1,仍会按任意字符拆分,不能替代转义句点。

验证时覆盖普通文本、连续句点、末尾句点、空字符串及不含句点的输入。没有匹配到分隔符时,结果包含原字符串;空输入也不能简单假定会返回长度为零的数组。

若下游按字段位置读取数据,应一起核对字段数量和空字段策略。上线前保留原始输入与旧规则,发现解析变化时回退局部规则并重新解析受影响记录,不要用忽略越界异常的方式吞掉数据。