
hasNext()仅检测是否存在下一个令牌但不消耗输入,若不调用next()等消费方法,会导致无限循环;需配合useDelimiter("\s+")处理多空格分隔,并始终记得关闭Scanner资源。
`hasnext()`仅检测是否存在下一个令牌但不消耗输入,若不调用`next()`等消费方法,会导致无限循环;需配合`usedelimiter("\s+")`处理多空格分隔,并始终记得关闭scanner资源。
在Java中,Scanner.hasNext()是一个常被误解的关键方法。根据Oracle官方文档,它“返回true当且仅当扫描器输入中还存在下一个令牌”,并特别强调:“扫描器不会越过任何输入”(The scanner does not advance past any input)——这句话正是理解问题的核心。
所谓“不越过输入”,意味着hasNext()纯粹是只读探测:它检查输入流头部是否能按当前分隔符匹配出一个有效token,但完全不移动内部指针、不跳过任何字符、不改变扫描状态。因此,在你的原始代码中:
while (sc.hasNext()) {
System.out.println("GOOD"); // ❌ 从未消费输入!
}每次循环都重复调用hasNext(),而输入流始终停留在字符串开头("Munich..."),由于首词"Munich"永远可被识别为合法token,hasNext()恒返回true,从而陷入死循环。
✅ 正确做法是:每次检测后必须调用消费方法(如next()、nextInt()等)来推进扫描位置。同时,Scanner默认以空白字符(s)为分隔符,但仅匹配单个空白;面对"Munich London"中多个连续空格时,可能因分隔符未规范化导致分割异常。因此推荐显式设置正则分隔符s+(匹配一个或多个空白字符):
立即学习“Java免费学习笔记(深入)”;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
String t = "Munich London Paris New_York";
Scanner sc = new Scanner(t).useDelimiter("\s+");
while (sc.hasNext()) {
System.out.println(sc.next()); // ✅ 每次循环消费一个token
}
sc.close(); // ⚠️ 必须显式关闭,避免资源泄漏
}
}输出结果为:
Munich London Paris New_York
关键注意事项总结:
-
hasNext()≠next():前者是条件判断,后者是实际读取并推进指针; - 分隔符需合理配置:对含多空格/制表符的字符串,优先使用
.useDelimiter("\s+"); - 类名遵循驼峰规范:
Main而非main; - 始终调用
sc.close()释放底层资源(尤其在处理文件流时至关重要); - 若仅需遍历而不处理具体值,仍需调用
next()(哪怕丢弃返回值),否则逻辑必卡死。
掌握这一机制,不仅能解决无限循环问题,更是深入理解Java I/O流状态管理的重要一步。


















