为何hasNext()会导致Java for循环无限运行?附正常while循环对比
先纠正你对hasNext()的理解错误
Scanner.hasNext()的逻辑是:输入流中还有可读取的令牌(token)时返回true,没有则返回false——你之前完全搞反了它的返回规则,这是核心误区。
第一段代码无限循环的原因
看这段代码:
for(int i = 0; standardInput.hasNext(); i++){ System.out.print(i); }
问题出在循环体内没有消费输入的令牌。当你输入内容后,Scanner会把输入的内容存成一个令牌放在缓冲区里。每次循环检查hasNext()时,它发现缓冲区里还有未读取的令牌,就一直返回true,循环条件永远成立。同时i不断自增,导致循环无限执行。
举个例子:你输入test回车后,缓冲区里就有了test这个令牌。第一次循环hasNext()返回true,输出0;第二次检查hasNext(),令牌还在缓冲区里,继续返回true,输出1;第三次输出2……以此类推,永远停不下来。
要修复这个循环,必须在循环体内调用next()系列方法读取并消费令牌,比如:
for(int i = 0; standardInput.hasNext(); i++){ System.out.print(i); standardInput.next(); // 读取并移除缓冲区里的令牌 }
这样每次循环都会把缓冲区的令牌拿走,当输入流没有更多令牌(比如按下Windows的Ctrl+Z或Linux的Ctrl+D结束输入),hasNext()返回false,循环就会终止。
第二段代码能正常运行的原因
再看这段代码的循环:
while(standardInput.hasNext()) { double nextNumber = standardInput.nextDouble(); sum += nextNumber; }
这里每次循环都会调用nextDouble()——这个方法会读取并消费输入流中的下一个浮点型令牌。每执行一次循环,缓冲区里的令牌就会被拿走处理一次,直到输入流中没有符合double类型的令牌(或者输入结束),hasNext()返回false,循环自然终止。
总结一下:两段代码的本质区别就是是否在循环中消费了输入令牌。第一段只检查不读取,令牌一直留在缓冲区,循环永不停止;第二段每次检查后都读取令牌,清空缓冲区,最终能正常结束。
内容的提问来源于stack exchange,提问作者Tila tila

