热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:JavaScanner的hasNext()方法

篇首语:本文由编程笔记#小编为大家整理,主要介绍了JavaScanner的hasNext()方法相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java Scanner的hasNext()方法相关的知识,希望对你有一定的参考价值。




Java Scanner的hasNext()方法

在编程笔试(或者某些场景)中,可能存在这样的需求:程序被要求接收不确定数量的一些字符串或者是数字,然后对接收的数据进行相关的处理。

假设这样一个场景,程序被要求接收不定数量的一些整数,然后计算这些数字的和。来看下面这个程序:

import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int sum = 0;
while(s.hasNextInt()) {
sum += s.nextInt();
}
System.out.println(sum);
}
}

我们的预期是:程序开始运行后,我们通过键盘在终端键入一行不定数量的整数,按下回车,程序紧接着打印出整数之和,然后结束运行。看上去似乎条例清晰,逻辑严密。不过程序实际运行的情况与我们的预期出现了一点偏差:在我们输入数据并按下回车之后,光标移动到了下一行,不过程序并没有打印出我们期待的结果,也没有结束运行,它“停下”了,或者说,它似乎在等待用户继续输入。如果此时你继续输入一行整数,然后按下回车,光标移动到下一行,情况不会发生变化。甚至你不输入任何内容,直接按下回车,情况仍然不会发生变化。但是如果你输入了一个浮点数或者是一个字符串,程序会紧接着打印出你想要的结果,然后结束运行。这很好理解,因为你输入的不是整数,循环会因此结束。

再来看这样一个场景,程序被要求接收不确定数量的一些字符串,然后将其逆序输出。来看下面这个程序:

import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
String str = "";
while(s.hasNext()) {
str = s.next() + " " + str;
}
System.out.println(str);
}
}

我们的预期是:程序开始运行后,我们通过键盘在终端键入一行不定数量的字符串,按下回车,程序紧接着逆序打印出字符串,然后结束运行。然而这个程序实际运行的情况更加糟糕,似乎不论我们输入任何类型、任何数量的内容,程序都不会从循环中跳出,就好像没有什么条件能够使s.hasNext()的结果为false

这种情况令人感到沮丧,看来我们必须调查一下到底哪里出现了问题。显而易见,问题的出现肯定和Scanner类的hasNext()方法有关,那就让我们首先来看一下 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() 方法的返回值看看:

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 // 这句是输入,下面的都是输出
true
your input is i
true
your input is am
true
your input is iron
true
your input is man
// 输出换行到这儿以后程序并未从循环中跳出


可以看到,程序将输入的最后一个单词man打印出以后,既没有跳出循环,打印出false;也没有进入下一次循环,打印出trues.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+D可以达到同样的效果,不过我没有做过相关的测试,仅仅在这里提一下。




方案二:使用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中读取内容,告别从键盘获取输入。

这个方案有一个优点是用户不再需要手动从键盘输入数据,尤其是当我们做测试的时候,这种方式能帮我们节省很多时间和精力,输入量越大,这种优势越为明显。IDEA中可以配置输入重定向,打开 Run Configurations 就可以找到,这里我不详细描述了。

另外,一些朋友提到:在编程网站中提交代码while(s.hasNext())可以自己跳出循环,而在本地 IDEA 中使用while(s.hasNext())没有办法退出循环,其实就是因为在线编程网站将输入流重定向了。




总结四种方案:
































方案号办法备注
方案一ctrl+ZWindows系统适用
方案二使用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



推荐阅读
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
author-avatar
机智的孙志嵘
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有