Scanner.hasNext(Pattern) 的真实作用是预匹配而非校验,它不消费输入流,仅判断下一个token是否完全匹配给定正则;默认按空白切分,若需整行匹配须先调用useDelimiter("A")或配合nextLine()手动校验。

Scanner.hasNext(Pattern) 的真实作用不是“校验”,而是“预匹配”
它不会消费输入流,只判断下一个 token(以默认分隔符 \p{javaWhitespace}+ 切分)是否能**完全匹配**给定正则。很多人误以为它能校验整行或任意位置的子串——其实不能。比如输入 "abc123def",用 Pattern.compile("\d+") 调用 hasNext() 会返回 false,因为整个 token 必须是纯数字,而 "abc123def" 是一个 token 且不满足。
常见错误:用错分隔符导致匹配失效
默认情况下,Scanner 按空白切分,所以 hasNext(Pattern) 只对单个 token 生效。若想校验一整行是否符合格式(如邮箱、日期),必须先切换分隔符:
- 调用
scanner.useDelimiter("\A")(匹配输入开始,等效于“不切分”)后,hasNext(Pattern)才会针对整段未消费的输入做匹配 - 更常用的是
scanner.nextLine()后手动用Pattern.matcher(string).matches(),反而更可控 - 若坚持用
hasNext()做行级校验,必须搭配useDelimiter("\R")(匹配换行符),再确保输入尚未被其他nextXxx()消费
正则写法陷阱:必须全匹配,不能用 ^ 和 $ 强行“补救”
hasNext(Pattern) 内部等价于 matcher.matches(),即隐式要求从头到尾完整匹配。因此:
- 写
Pattern.compile("^[a-z]+@.*\.com$")是多余的——^和$在matches()中本就自动生效 - 错误写法:
Pattern.compile("com")→ 匹配失败,因为只含子串,不满足全匹配 - 正确写法:
Pattern.compile("[a-z]+@[a-z]+\.com")(注意转义点号) - 如果需要可选部分,用
?或(?:...)?,别漏掉所有分支路径
性能与线程安全提醒
hasNext(Pattern) 每次都新建 Matcher 并重置状态,频繁调用(如循环中)会有对象开销;若模式固定,建议复用 Pattern 实例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
private static final Pattern EMAIL_PATTERN = Pattern.compile("[a-z]+@[a-z]+\.[a-z]{2,}");
另外,Scanner 不是线程安全的——多线程共用同一个实例时,hasNext(Pattern) 和后续 next() 之间可能被其他线程插入消费,导致匹配结果和实际取到的内容不一致。
真正容易被忽略的是:一旦调用过 next()、nextInt() 等方法,输入流已前进,再调用 hasNext(Pattern) 面对的是下一个 token,而非刚才那个。预校验逻辑必须严格串行,且不能混用不同类型的 nextXxx() 调用。

















