当前位置: 首页 > 知识库问答 >
问题:

扫描器#nextline()会留下一个剩余的换行符

郗丰
2023-03-14

我最近遇到扫描仪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("\nOne 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 <------------- prompts for input, as expected
    */

// 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.
                                         <------------ leftover newline printed, as expected
    Please enter a month in numeric form <---------------- does not prompt for input due to another leftover newline (why?)
    java.util.InputMismatchException

    One of your inputs was not valid.
    badinput <----------------------- prints badinput even though it should've been consumed on the last iteration (why?)
    Please enter a month in numeric form
    */

在有人将其标记为重复之前,请理解我已经查看了stackoverflow上的next和nextLine之间的差异。nextLine应该使用换行符,但这里似乎没有这样做。多谢了。

共有1个答案

阚正真
2023-03-14
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,我们将使用剩余的行分隔符,而不是nextLine中的值,

因此,由于else块只是抛出异常,它将控制流移动到catch部分。这意味着我们将跳过break,因此我们的循环将需要再次迭代。

现在在catch部分,您只需打印

System.err.println(e);
System.out.println("\nOne of your inputs was not valid.");
System.out.println(input.nextLine());

它打印异常e和字符串“\none of your inputs was not valid”。nextLine()的结果(如前面所解释的)只会消耗上次nextInt()调用后保留的行分隔符,因此我们仍然没有消耗扫描程序中的badinput

这意味着当循环启动另一个迭代并请求month时,它接收到的BATInput是无效的Int,因此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);

要避免多次编写此代码,请创建您自己的实用程序方法。您甚至可以跳过要求from 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");

您可以添加该实用程序方法另一个版本,在该版本中,您可以让程序员添加数字应该通过的条件。我们可以使用Java 8中添加的IntPredicate函数接口,这将允许我们使用lambdas创建条件,如

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.nextLine()有关。 我不是很清楚为什么,但由于某种原因,有时我必须按一次enter键,然后我的代码才会接受我的输入并将其存储为变量。本质上,我最终输入了两次输入。我尝试在代码周围插入Scanner.nextLine()以“占用

  • 我有两个do-while循环用于进行自定义输入验证。问题是它会自动进入下一个do while循环。正确插入名称后,我必须放置一个新的下一行():name=scanner。nextLine() 我知道当光标停留在那里时,nextLine()会出现“小故障”,您必须调用nextLine()才能继续。资料来源:https://www.geeksforgeeks.org/why-is-scanner-sk

  • 在Java方面,我是一个业余爱好者,所以请原谅我的问题,如果它看起来很愚蠢:-P我有以下代码,旨在计算文件中的行数: 所以它很好,但我想将扫描仪重新用于其他目的,但nextLine已移动到文件的最后一行,我想将其重置回第一行。 (取而代之的是,我不得不使用另一台扫描仪来实现另一个目的,而在我看来,这似乎没有它应有的优雅。) 我肯定肯定有一种扫描仪方法可以将计数器重置为零? 谢谢 CJ

  • 首先为标题感到抱歉,想不出别的了。我目前正在完成一个关于JetBrains Hyperskill的项目,该项目是一个单位转换器,用户可以在其中转换重量、长度和温度单位。我几乎完成的项目,转换工作很好,但我有一个问题与用户输入。 用户输入由以下部分组成: 因此,用户可以输入如下内容: null null -要转换的数量 -这应该是像“摄氏”和“摄氏度”这样的输入 -随机单词 -这也应该读取输入,如“

  • 我有下面的代码 每次我输入名字,然后点击回车,什么也没有发生我再次输入名字,什么也没有发生,我第三次输入名字,这里,它打印出来。第二个字符串也会出现同样的情况 我不明白会有什么问题。