java中Scanner的hasNext用法细节
声明:本文转载优快云博主「realzhangsan」的原创文章,原文链接:https://blog.youkuaiyun.com/hanqingupc/article/details/121799598,希望多多支持原文博主,谢谢!
首先来看一下 jdk 的开发者对这个方法的描述:
Returns true if this scanner has another token in its input.
This method may block while waiting for input to scan.
The scanner does not advance past any input.
重点看这一句:This method may block while waiting for input to scan. 意思是hasNext()方法在等待输入时可能会产生阻塞。
举例:循环体里面打印一下 hasNext() 方法的返回值:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
boolean b;
while(b = s.hasNext()) {
System.out.println(b);
System.out.println("your input is " + s.next());
}
System.out.println(b);
}
程序执行的结果如下:
输入:i am iron man
打印hasNext()的值:true
输出:your input is i
循环1:打印hasNext()的值:true
输出:your input is am
循环2:打印hasNext()的值:true
输出:your input is iron
循环3:打印hasNext()的值:true
输出:your input is man
最后一遍循环完成后,程序并未从循环中跳出,且hasNext()并未出现false,所以s.hasNext()在这儿发生了阻塞,程序在等待用户输入,而用户不想再继续输入了。一方面,程序并不把空格、制表符以及回车换行这样的不可见字符当作输入,空白字符被当作输入内容的分隔符,回车换行则被用于提交输入;另一方面,似乎用户输入任何可见字符,s.hasNext()都会返回true。
解决的办法不止一种,如下:
方案一(Windows系统适用):Ctrl + Z
如果是在Windows系统的cmd窗口中运行此程序,按下Ctrl + Z,窗口会出现^Z这样的符号,按下回车,程序打印出false,然后结束运行。请注意,程序是正常结束的,所以说:并非用户输入任何可见字符,s.hasNext()都会返回true,将^Z作为输入,hasNext()会返回false。这个方案在cmd窗口中有效,而在IDEA自带的控制台中无效,不过在IDEA中按下Ctrl+D可以达到同样的效果。
另外,有StackOverflow用户指出,对于Linux/Unix/MacOS环境,Ctrl + Z可以达到同样的效果,不过我没有做过相关的测试,仅仅在这里提一下。
方案二:使用hasNext(String pattern)
可以使用hasNext()的重载方法hasNext(String pattern)通过特殊终止符结束循环,就像下面这样:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
while(!s.hasNext("exit")) {
System.out.println("your input is " + s.next());
}
}
当输入exit,循环结束。有点类似于在mysql命令行程序中输入quit,或者是在cmd中输入exit。
方案三:使用break跳出循环
在循环体中通过特殊终止符触发break,例如下面这样:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
while(s.hasNext()) {
String tmp = s.next();
if(tmp.equals("quit")) break;
System.out.println("your input is " + tmp);
}
}
当输入quit,循环终止。
方案四:重定向输入流
前面说过,hasNext()方法可能会在等待输入时阻塞,可能的意思就是说:存在某种情况,hasNext()不会发生阻塞。比如说下面介绍的这种方案:
既然问题是由键盘输入带来的,不如就把产生问题的源头干掉,我们可以重定向标准输入使得系统从文件而不是从键盘读取输入。操作很简单,提前在一个文本文件中编辑好输入内容,然后在cmd中执行程序,只需给执行命令增加一点内容,像下面这样:
java Test < text.txt //text.txt
中包含了待输入的内容。
按下回车,程序从text.txt中读取内容,告别从键盘获取输入。
这个方案有一个优点是用户不再需要手动从键盘输入数据,尤其是当我们做测试的时候,这种方式能帮我们节省很多时间和精力,输入量越大,这种优势越为明显。IDEA中可以配置输入重定向,打开 Run Configurations 就可以找到,这里我不详细描述了。
另外,一些朋友提到:在编程网站中提交代码while(s.hasNext())可以自己跳出循环,而在本地 IDEA 中使用while(s.hasNext())没有办法退出循环,其实就是因为在线编程网站将输入流重定向了。
总结四种方案:
方案号 | 办法 备注 |
---|---|
方案一 | (Windows系统适用):ctrl + Z |
方案二 | 使用hasNext(String pattern) |
方案三 | 使用break跳出循环 最朴素的思路 |
方案四 | 重定向输入流 节省时间和精力 |
参考资料:
[1] Robert Sedgewick and Kevin Wayne 著,谢路云 译.算法.北京:人民邮电出版社,2012:24.
[2] trutheality.StackOverflow.https://stackoverflow.com/questions/10490344/how-to-get-out-of-while-loop-in-java-with-scanner-method-hasnext-as-condition
[3] while(hasNextInt())为什么不会结束循环.百度知道.https://zhidao.baidu.com/question/135843130068219805.html
[4] java的Scanner类的hasNext()方法问题.百度知道.https://zhidao.baidu.com/question/505075549.html
[5] 如何在JAVA中使用SCANNER方法“HASNEXT”作为条件退出WHILE循环?.dovov编程网.http://www.dovov.com/javascannerhasnextwhile.html