Java StringTokenizer 怎样把分隔符也作为 token 返回
来源:17golang原创
时间:2026-11-08 02:03:59 318浏览 收藏
在处理一段轻量配置或表达式时,很多人会发现普通分词只留下文字,却把逗号、等号、竖线这类符号丢掉了。如果后续还要根据符号判断格式,就不能只拿到内容 token。
Java 的 StringTokenizer 可以通过三参数构造器解决这个问题:把第三个参数 returnDelims 设为 true,分隔符会以独立 token 返回;设为 false 时,分隔符只负责切分,不会出现在结果里。
官方文档:https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/StringTokenizer.html
先看懂 returnDelims 到底改变了什么
StringTokenizer 把 delim 参数中的每一个字符都视为分隔符。第三个参数并不是“是否保留整段分隔字符串”,而是决定这些分隔符字符是否也参与 token 输出:
false:分隔符被跳过,只返回连续的非分隔符字符。true:每个分隔符字符本身也是一个 token,非分隔符字符仍按连续片段组成 token。
例如输入 name=alice|role=admin,分隔符设置为 =| 时,保留分隔符后的逻辑序列是 name、=、alice、|、role、=、admin。这正适合需要继续识别键值边界的轻量解析。

用三参数构造器保留分隔符
关键写法是 new StringTokenizer(text, delimiters, true)。遍历时先调用 hasMoreTokens(),确认还有内容后再调用 nextToken(),这样不会在取尽 token 后误触发异常。
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class KeepDelimiters {
public static void main(String[] args) {
String text = "name=alice|role=admin";
// delim 中的每个字符都是独立分隔符,这里要保留等号和竖线。
StringTokenizer tokenizer = new StringTokenizer(text, "=|", true);
List tokens = new ArrayList();
// 先判断是否还有 token,再读取,避免读空后抛出 NoSuchElementException。
while (tokenizer.hasMoreTokens()) {
tokens.add(tokenizer.nextToken());
}
// 结果按原始顺序保留内容与符号的边界。
System.out.println(tokens);
}
}
按 API 对 returnDelims=true 的定义,这段示例得到的序列应为:
[name, =, alice, |, role, =, admin]
这里的重点不是把列表直接打印出来,而是保留了原字符串中“内容—符号—内容”的相邻关系。后续代码可以根据 = 识别赋值边界,根据 | 识别记录边界。
连续分隔符不会合并成一个 token
使用 true 后,分隔符是单独返回的字符 token。连续出现的分隔符会分别返回,而不会自动合并。例如输入 a,,b,分隔符为逗号,概念上的 token 序列是 a、,、,、b。
这和许多“按字段切分”的直觉不同:StringTokenizer 不会把连续分隔符变成一个空字段,也不会把两个逗号包装成 ,,。如果业务需要识别空字段,应在消费 token 时记录相邻分隔符,或者直接选择能明确表达空字段规则的解析方式。
还要注意 delim 是字符集合,不是一个完整字符串。例如传入 "->",含义是 - 和 > 都是分隔符,不是把 -> 当作一个双字符分隔符。需要匹配多字符分隔符时,StringTokenizer 就不是合适的工具。
Unicode 分隔符和遍历边界怎么处理
Oracle 的 API 文档特别说明:当 returnDelims 为 true 时,分隔符会以一个 Unicode code point 的字符串返回;某些 code point 可能占用两个 char。因此,不能把“一个 token”简单等同为“一个 UTF-16 char”。
遍历边界也要分清:
- 构造器的
str为null时会抛出NullPointerException。 hasMoreTokens()返回false后,继续调用无参nextToken()会抛出NoSuchElementException。countTokens()计算剩余 token 数量,但不会推进当前读取位置。
如果输入来自可选配置,建议在创建 tokenizer 前先明确空值策略;如果输入可能为空字符串,则可以正常创建对象,只是遍历时不会得到 token。

什么时候该换成 split 或正则表达式
StringTokenizer 是保留兼容性的旧接口。Java SE 26 的官方文档仍保留它,但同时建议新代码优先考虑 String.split 或 java.util.regex。因此,是否使用它应该看任务边界:
| 需求 | 更合适的选择 | 原因 |
|---|---|---|
| 简单字符分隔,并且要把每个分隔符保留下来 | StringTokenizer(..., true) | 调用短,遍历顺序直观 |
| 需要多字符分隔符、捕获组或复杂模式 | Pattern / Matcher | 正则表达式能表达更丰富的边界 |
| 只需要字段数组,并有明确的空字段规则 | String.split | 结果更贴近“字段切分”模型 |
| 要解析带引号、转义或嵌套结构的文本 | 专用解析器或状态机 | 单字符分隔器无法表达语法上下文 |
换句话说,returnDelims=true 能解决“符号不能丢”的小问题,但它不会让 StringTokenizer 变成完整的词法分析器。分隔符集合、连续符号、Unicode code point 和空字段语义都应在设计时写清楚。
几个容易混淆的问题
returnDelims=true 会返回空字符串吗?
它返回的是分隔符字符 token,不是由两个分隔符之间的间隔自动生成的空字符串。连续分隔符需要由调用方根据相邻 token 自己解释。
能不能把 "::" 当作一个分隔符?
不能。StringTokenizer 会把 delim 中的每个字符分别看待,因此两个冒号会分别参与切分。
为什么要用 hasMoreTokens() 包住 nextToken()?
因为 nextToken() 在没有剩余 token 时会抛出 NoSuchElementException。循环条件既表达了读取意图,也把异常边界放在了调用前。
小结
要让 Java StringTokenizer 返回分隔符,使用三参数构造器并将第三个参数设为 true:
// 第三个参数为 true,分隔符会以独立 token 返回。 StringTokenizer tokenizer = new StringTokenizer(text, "=|", true);
记住四点即可:分隔符集合按单字符解释;连续分隔符逐个出现;Unicode 分隔符按 code point 处理;新项目若需要复杂模式或明确空字段,优先评估 split、正则或专用解析器。
-
Golang · Go教程 | 2个月前 | 标准库 · golang · 测试 · go · 迭代器 · 字符串处理 · Go 迭代器 换行 range over function strings.Lines470 收藏
-
Golang · Go教程 | 2个月前 | 标准库 · 性能优化 · 字符串处理 · Go教程 · 内存分配 strings.Split Go 1.24 Go 迭代器 Go strings.SplitSeq363 收藏
-
184 收藏
-
164 收藏
-
Golang · Go教程 | 2个月前 | 标准库 · 性能 · 迭代器 · 字符串处理 · Go教程 · Go Go 1.24 iter.Seq strings.SplitAfterSeq 字符串分段141 收藏
-
391 收藏
-
185 收藏
-
346 收藏
-
文章 · java教程 | 58分钟前 | Java · 并发编程 · CompletableFuture · java completablefuture obtrudeException 异步异常恢复161 收藏
-
258 收藏
-
文章 · java教程 | 1小时前 | nio · Java教程 · 文件系统 · java 文件属性 nio Files.readAttributes BasicFileAttributes NOFOLLOW_LINKS243 收藏
-
268 收藏
-
220 收藏
-
104 收藏
-
458 收藏
-
396 收藏
-
文章 · java教程 | 1天前 | 资源管理 · Java教程 · java arena scope MemorySegment FFM Foreign Function and Memory 本地内存300 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习