我一直面临着扫描仪# nextline的问题。 根据我的理解,nextLine ) )应该返回到当前输入流的剩馀部分,并进行下一行。
while (真)。
try{
system.out.println (pleaseenteramonthinnumericform );
month=input.nextInt (;
system.out.println (pleaseenteradayinnumericform );
day=input.nextInt (;
system.out.println (pleaseenteratwo-digit year );
if(input.hasnextint ()==true ) )。
year=input.next (;
}
else{
throw new Java.util.inputmismatchexception (;
}
布雷克;
}
catch(exceptione ) {
系统. err.println (e;
System.out.println ('
One of your inputs was not valid.';
system.out.println (input.nextline ();
}
}
问题是最后一行。 如果将其保留为input.nextLine (),则循环的下一次迭代将接受月份换行符。 这是为什么? 对catch块中nextLine的调用是否占用了剩下的包含换行符的行,并且在下一次迭代中是否应该正确提示用户? 注意:我决定把它们打印出来,弄清楚发生了什么,但没有雪茄。
我从终端收集了一些输出来解释我的意思:
//whatshouldhappen (thisiswhencatchcontainsinput.next ) (rather than nextLine ) )。
/*
Please enter a month in numeric form
8
please enter a day name (optional,probably does not need a translation )
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
*/
//whathappenswhenihavenextlineinthecatchblock (代码有效) )。
/*
Please enter a month in numeric form
8
please enter a day name (optional,probably does not need a translation )
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
*/
请理解,在有人将其标记为重复之前,您已经看到了堆栈概述中的nextLine和nextLine之间的差异。 nextLine应该使用换行符,但在这里似乎不会这样做。 谢谢你。
if(input.hasnextint(==true )与if (input.hasnext int ) )相同。 为什么是现实的?
(if(input.hasnextint(==true )//prefer`if(input.hasnextint ) ) ) ) ) ) 0
year=input.next (;
} else {
throw new Java.util.inputmismatchexception (;
}
如果输入badinput,input.hasNextInt ()将计算为false。 也就是说,在不消耗badinput的情况下执行else块。 为此,必须调用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()来解决问题。