StringTokenizer与split()的核心差异在于分割逻辑:前者跳过空字段、仅支持字面量分隔符、Unicode兼容性差且无流式控制;后者保留空字段(末尾除外)、支持正则分隔符、Unicode友好并提供limit和Stream支持。

StringTokenizer 和 split() 在变量分割上的核心差异,不在于“能不能分”,而在于“怎么分”和“分出什么”。它们对相同输入可能产生完全不同的结果,尤其在空字段、分隔符连续、转义处理等边界场景下。
空字段是否保留
这是最直观也最容易踩坑的区别:
-
String.split() 默认保留空字段(除非末尾连续分隔符被截断):
"a,,b".split(",")→["a", "", "b"](长度为3)"a,b,,c,".split(",")→["a", "b", "", "c"](末尾空串被丢弃,因limit=0的默认行为) -
StringTokenizer 直接跳过所有空字段:
new StringTokenizer("a,,b", ",")→ 遍历时只返回"a"和"b"(countTokens()返回 2)
它不认为""是一个合法 token,语义上是“按分隔符切开后取非空块”。
分隔符是否可配置为正则表达式
决定了灵活性与使用成本:
-
split() 第一个参数是正则表达式:
支持
"\s+|[,;]"(匹配空白或多字符分隔符),"\|"(需转义管道符); 但写错正则(如split("."))会导致全字符串被拆成单字符数组——因为.在正则中匹配任意字符。 -
StringTokenizer 的分隔符是字面量字符串:
new StringTokenizer("a|b|c", "|")直接生效,无需转义; 但它不支持“或”逻辑(比如不能同时用|和;作为分隔符,除非手动拼接成"|;"并逐字符匹配)。
对特殊字符和 Unicode 的兼容性
影响现代文本(含 emoji、中文标点、控制字符)的正确解析:
-
split() 基于
Pattern,天然支持 Unicode 字符类(如"\p{Z}"匹配各类空白)、补充字符(如 ?)和 UTF-16 代理对; -
StringTokenizer 在 JDK 7u6 后已不再共享底层数组,且无法正确识别 Unicode 补充字符(如某些 emoji 会被截断);
它也不能处理
u0000(NUL 字符),会提前终止解析; 对中文逗号、全角分号等“看起来像分隔符”的字符,只能当作普通字符匹配,无智能识别能力。
是否支持流式处理与控制粒度
关系到内存占用和大文本处理安全:
-
split() 提供
split(regex, limit):"a,b,c,d".split(",", 3)→["a", "b", "c,d"],避免生成超长数组;
Java 8+ 还可配合Pattern.compile(delim).splitAsStream(text)实现真正的按需消费,不加载全部结果到内存。 - StringTokenizer 没有 limit 机制:必须遍历全部 token 才知道总数; 不支持跳过前导/尾随分隔符; 无法判断某个 token 是否来自开头或结尾位置; 更无法与 Stream 或函数式接口自然衔接。










