java input.nextline_关于java:Scanner#nextLine()留下一个剩余的换行符[通俗易懂]

java input.nextline_关于java:Scanner#nextLine()留下一个剩余的换行符[通俗易懂]我一直遇到Scanner#nextLine的问题。根据我的理解,nextLine()应该返回当前输入流的其余部分,然后继续进行下一行。while(true){try{System.out.println(“Pleaseenteramonthinnumericform”);month=input.nextInt();System.out.println(“Pleaseenter…

大家好,又见面了,我是你们的朋友全栈君。

我一直遇到Scanner#nextLine的问题。 根据我的理解,nextLine()应该返回当前输入流的其余部分,然后继续进行下一行。

while (true){

try{

System.out.println(“Please enter a month in numeric form”);

month = input.nextInt();

System.out.println(“Please enter a day in numeric form”);

day = input.nextInt();

System.out.println(“Please enter a two-digit year”);

if (input.hasNextInt() == true){

year = input.next();

}

else{

throw new java.util.InputMismatchException();

}

break;

}

catch(Exception e){

System.err.println(e);

System.out.println(“

One of your inputs was not valid.”);

System.out.println(input.nextLine());

}

}

问题是最后一行。 如果我将其保留为input.nextLine(),则循环的下一次迭代将接受月份的换行符。 这是为什么? 在catch块中对nextLine的调用是否不应该占用其余的行(包括换行符)并在下一次迭代中正确提示用户? 注意:我已决定打印它们以尝试弄清楚发生了什么,但没有雪茄。

我已经从终端收集了一些输出来说明我的意思:

// What should happen (this is when catch contains input.next() rather than nextLine)

/*

Please enter a month in numeric form

8

Please enter a day in numeric form

2

Please enter a two-digit year

badinput

java.util.InputMismatchException

One of your inputs was not valid.

badinput

Please enter a month in numeric form

*/

// What happens when I have nextLine in the catch block (code above)

/*

Please enter a month in numeric form

8

Please enter a day in numeric form

2

Please enter a two-digit year

badinput

java.util.InputMismatchException

One of your inputs was not valid.

Please enter a month in numeric form

java.util.InputMismatchException

One of your inputs was not valid.

badinput

Please enter a month in numeric form

*/

在有人将其标记为重复之前,请理解我已经看过stackoverflow上的nextLine和nextLine之间的区别。 nextLine应该使用换行符,但是这里似乎不这样做。 谢谢。

if (input.hasNextInt() == true){与if (input.hasNextInt()){相同。 为什么要比较真实?

if (input.hasNextInt() == true) { // prefer `if(input.hasNextInt())`

year = input.next();

} else {

throw new java.util.InputMismatchException();

}

输入badinput会将input.hasNextInt()评估为false,这意味着将执行else块而不消耗该badinput(为此,我们需要调用next()-而不是nextLine(),因为您可能知道是否我们在nextInt之后使用nextLine,我们将消耗剩余的行分隔符,而不是next的值,在Scanner处的更多信息是在使用next(),nextInt()或其他nextFoo()方法之后跳过nextLine())。

因此,由于else块仅引发异常,因此它将控制流移至catch部分。这意味着我们正在跳过break,因此我们的循环将需要再次迭代。

现在在捕获部分,您只需打印

System.err.println(e);

System.out.println(“

One of your inputs was not valid.”);

System.out.println(input.nextLine());

打印异常e,字符串”

One of your inputs was not valid.”和nextLine()的结果(如前所述)将仅消耗最后一个nextInt()调用后仍保留的行分隔符,因此我们仍然没有使用Scanner中的badinput。

这意味着当循环开始另一个迭代并要求月份时,它会收到无??效的int batinput,因此nextInt()会抛出InputMismatchException。再一次,我们以catch块结束,并调用nextLine(),这一次消耗了badinput。

现在,由于我们最终消耗掉了那个不正确的值循环,因此将开始另一个迭代,并且将要求我们提供月份的值。

为了避免此类问题,请阅读以下示例:使用java.util.Scanner验证输入。在第一个示例中,您将找到在提供每个输入时对其进行验证的方法

Scanner sc = new Scanner(System.in);

int number;

do {

System.out.println(“Please enter a positive number!”);

while (!sc.hasNextInt()) {

System.out.println(“That’s not a number!”);

sc.next(); // this is important!

}

number = sc.nextInt();

} while (number <= 0);

System.out.println(“Thank you! Got” + number);

为避免多次编写此代码,请创建自己的实用程序方法。您甚至可以跳过要从数字开始为正数的条件,例如:

public static int getInt(Scanner sc, String askMsg) {

System.out.println(askMsg);

while (!sc.hasNextInt()) {

System.out.println(“That’s not a number. Please try again”);

sc.next(); // consuming incorrect token

}

//here we know that next value is proper int so we can safely

//read and return it

return sc.nextInt();

}

使用这种方法,您的代码可以简化为

Scanner input = new Scanner(System.in);

int month = getInt(input,”Please enter a month in numeric form”);

int day = getInt(input,”Please enter a day in numeric form”);

int year = getInt(input,”Please enter a two-digit year”);

您可以添加该实用程序方法的另一个版本,在该版本中,您可以让程序员添加应该传递该数字的条件。我们可以将IntPredicate功能接口用于Java 8中添加的接口,这将允许我们使用lambda这样的条件来创建条件

public static int getInt(Scanner sc, String askMsg, IntPredicate predicate) {

System.out.println(askMsg);

int number;

boolean isIncorrect = true;

do {

while (!sc.hasNextInt()) {

String value = sc.next(); // consuming incorrect token

System.out.println(value +” is not valid number. Please try again”);

}

number = sc.nextInt();

if (!predicate.test(number)) {

System.out.println(number +” is not valid number. Please try again”);

}else{

isIncorrect=false;

}

} while (isIncorrect);

return number;

}

用法:

int year = getInt(input,”Please enter a two-digit year”, i -> (i>=10 && i<=99));

请记住,Scanner看不到您的打印语句,它只是将输入作为字符流读取。作为用户,您一次只能输入一行字符对于扫描仪来说是没有意义的。

因此,您键入8(其中代表操作系统的实际换行符)。 nextInt()之后,8已被消耗。

然后,键入2,使暂挂输入为2。记住,到目前为止,仅消耗了8。 nextInt()然后跳过空格并返回2,从而消耗了2。

然后,键入badinput,使暂挂输入为badinput。由于下一个令牌不是有效的整数,因此将引发异常,并输入catch块,在其中调用nextLine()。它使用直到第一个的所有字符,并返回之前的文本,即空字符串。

此时,badinput仍在流中挂起,并在循环播放时进行处理。

这是人们使用Scanner的主要缺陷之一。 nextInt()不消耗行,仅消耗令牌,而将其余的行留在后面。

Scanner如何使事情恶化的示例:

Please enter a month in numeric form

8 2 17

Please enter a day in numeric form

Please enter a two-digit year

因为用户在第一行输入了所有3个值,所以您的代码将获得这些值,但是即使没有必要,仍将打印接下来的两个提示。那样很奇怪。

解决方案1:不要使用Scanner。这太奇怪了。太容易使用了,太容易误用了,也就是太难正确使用了。

解决方案2:在每个nextInt()之后调用nextLine(),以刷新(静默使用)接受值之后的所有多余文本。如果这样做,示例将如下所示:

Please enter a month in numeric form

8 2 17

Please enter a day in numeric form

2

Please enter a two-digit year

17

第一行中的217将被静默忽略。

如果需要完整的错误处理,可以将逻辑扩展到if (! nextLine().trim().isEmpty()) {/*ERROR*/}。

我怀疑当您输入两位数的年份时,以及您使用next()读取它时,它将仅读取下一个字符串。并且即使您输入2位数字的年份,它也将由nextLine()新行或空值读取2,即使输入了无效值,此后的任何内容(包括新行或回车符)都将保留。因此,您在catch中的nextLine()只会读取部分无效输入的剩余内容,而保留新行或回车符。当您希望提示符显示为读取月份时,这会导致发生异常。您可以在每个nextInt()或next()之后放置nextLine()来解决问题。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144020.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月11日 下午8:00
下一篇 2022年5月11日 下午8:20


相关推荐

  • eclipse500错误原因解决方法_eclipse运行无法显示网页

    eclipse500错误原因解决方法_eclipse运行无法显示网页eclipse内部浏览器报错:此错误(HTTP500内部服务器错误)意味着您正在访问的网站出现了服务器问题,此问题阻止了该网页的显示修改eclipse设置即可解决:window-&gt;preferences-&gt;general-&gt;webbrowser选择使用外部浏览器即可IE浏览器设置如下:https://blog.csdn.net/txwtech/article/details…

    2022年8月11日
    12
  • [C#] 剖析 AssemblyInfo.cs – 了解常用的特性 Attribute

    [C#] 剖析 AssemblyInfo.cs – 了解常用的特性 Attribute剖析 AssemblyInfo.cs-了解常用的特性Attribute【博主】反骨仔【原文】http://www.cnblogs.com/liqingwen/p/5944391.h

    2022年7月2日
    26
  • 图像配准算法大总结

    图像配准算法大总结博客总结 点击打开链接一 图像配准定义图像配准是图像处理研究领域中的一个典型问题和技术难点 其目的在于比较或融合针对同一对象在不同条件下获取的图像 例如图像会来自不同的采集设备 取自不同的时间 不同的拍摄视角等等 有时也需要用到针对不同对象的图像配准问题 具体地说 对于一组图像数据集中的两幅图像 通过寻找一种空间变换把一幅图像映射到另一幅图像 使得两图中对应于空间同一位置的点一一对应起来 从

    2026年3月19日
    2
  • 阈值分割法简述

    阈值分割法简述阈值分割法 nbsp nbsp nbsp nbsp nbsp nbsp nbsp 阈值分割法分为全局阈值法和局部阈值分割法 所谓局部阈值分割法是将原始图像划分成较小的图像 并对每个子图像选取相应的阈值 在阈值分割后 相邻子图像之间的边界处可能产生灰度级的不连续性 因此需用平滑技术进行排除 局部阈值法常用的方法有灰度差直方图法 微分直方图法 局部阈值分割法虽然能改善分割效果 但存在几个缺点 1 每幅子图像的尺寸不能太小 否则统计出的结果无意义

    2026年3月19日
    2
  • 默认网关 计算机网络_计算机网络默认网关

    默认网关 计算机网络_计算机网络默认网关什么是网关?  大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信息,也必须经过一道“关口”,这道关口就是网关。顾名思义,网关(Gateway)就是一个网络连接到另一个网络的“关口”。按照不同的分类标准,网关也有很多种。TCP/IP协议里的网关是最常用的,在这里我们所讲的“网关”均指TCP/IP协议下的网关。  网关实质上是一个网络通向其他网络的IP地址…

    2025年7月13日
    3
  • 超详细“CIDR地址块及其子网划分”

    超详细“CIDR地址块及其子网划分”转自 https blog csdn net dan article details CIDR 地址块及其子网划分 内含原始 IP 地址分类及其子网划分的介绍 CIDR 概述及其地址块计算 CIDR 中文全称是无分类域间路由选择 英文全称是 ClasslessInt DomainRoutin 在平常 大家多称之为无分类编址 它也是构成超网的一种技术实

    2026年3月17日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号