Java 如何使用 Scanner 处理由无效输入(InputMismatchException)引起的无限循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3572160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 01:58:20  来源:igfitidea点击:

How to handle infinite loop caused by invalid input (InputMismatchException) using Scanner

javajava.util.scannerinfinite-loop

提问by mateusmaso

So, I'm getting stuck with this piece of code:

所以,我被这段代码困住了:

import java.util.InputMismatchException;
import java.util.Scanner;

public class ConsoleReader {

    Scanner reader;

    public ConsoleReader() {
        reader = new Scanner(System.in);
        //reader.useDelimiter(System.getProperty("line.separator"));
    }

    public int readInt(String msg) {
        int num = 0;
        boolean loop = true;

        while (loop) {
            try {
                System.out.println(msg);
                num = reader.nextInt();

                loop = false;
            } catch (InputMismatchException e) {
                System.out.println("Invalid value!");
            } 
        }
        return num;
    }
}

and here is my output:

这是我的输出:

Insert a integer number:
Invalid value!
Insert a integer number:
Invalid value!
...

插入一个整数:
无效值!
插入一个整数:
无效值!
...

采纳答案by samitgaur

As per the javadocfor Scanner:

根据扫描仪的javadoc

When a scanner throws an InputMismatchException, the scanner will not pass the token that caused the exception, so that it may be retrieved or skipped via some other method.

当扫描器抛出 InputMismatchException 时,扫描器不会传递导致异常的令牌,因此可以通过其他方法检索或跳过它。

That means that if the next token is not an int, it throws the InputMismatchException, but the token stays there. So on the next iteration of the loop, reader.nextInt()reads the same token again and throws the exception again. What you need is to use it up. Add a reader.next()inside your catchto consume the token, which is invalid and needs to be discarded.

这意味着如果下一个标记不是int,它会抛出InputMismatchException,但标记会留在那里。所以在循环的下一次迭代中,reader.nextInt()再次读取相同的标记并再次抛出异常。你需要的是用完它。reader.next()在你里面加一个catch消费token,这个token是无效的,需要丢弃。

...
} catch (InputMismatchException e) {
    System.out.println("Invalid value!");
    reader.next(); // this consumes the invalid token
} 

回答by cohensh

What I would do is read in the whole line using Scanner.nextLine(). Then create another scanner that reads the returned string.

我要做的是使用 Scanner.nextLine() 读取整行。然后创建另一个扫描器来读取返回的字符串。

String line = reader.nextLine();
Scanner sc = new Scanner(line);

This would make your sample function something like this:

这将使您的示例函数如下所示:

  public int readInt(String msg) {
        int num = 0;
        boolean loop = true;

        while (loop) {
            try {
                System.out.println(msg);
                String line = reader.nextLine();
                Scanner sc = new Scanner(line);
                num = sc.nextInt();   
                loop = false;
            } catch (InputMismatchException e) {
                System.out.println("Invalid value!");

            } 
        }
        return num;
    }

This way you have one scanner that gets the input and one that validates it so you don't have to worry about reader caring if they input the correct form of input.

通过这种方式,您拥有一台获取输入的扫描仪和一台验证输入的扫描仪,因此您不必担心读者是否关心他们是否输入了正确的输入形式。

回答by Hendra Jaya

The guard of your while-do is 'loop' variable.

你的while-do 的守卫是'loop' 变量。

The exception itself thrown before your code reaches assignment loop = false; To be precise, the exception is thrown in previous statement which is num = reader.nextInt();

在您的代码到达赋值 loop = false; 之前抛出的异常本身;准确地说,异常是在前面的语句 num = reader.nextInt(); 中抛出的。

When exception thrown, value of 'loop' variable is 'true' but your code jumps to catch block and then repeats the while-do. This while-do will never stop because next iteration will throw an exception again, jumps to catch block again and so on.

抛出异常时,“loop”变量的值为“true”,但您的代码跳转到 catch 块,然后重复 while-do。这个 while-do 永远不会停止,因为下一次迭代将再次抛出异常,再次跳转到 catch 块等等。

To terminate this while-do, you need to guard your while-do with another logical thing such as :

要终止此 while-do,您需要使用另一个合乎逻辑的事物来保护您的 while-do,例如:

  1. Exit when reader gets non-int character
  2. Exit when EOF
  1. 当读者获得非整数字符时退出
  2. EOF 时退出

This can be done in catch block or some other lines. But precise solution depends on your specifications.

这可以在 catch 块或其他一些行中完成。但精确的解决方案取决于您的规格。

回答by jerjer

You may also try this:

你也可以试试这个:

   public int readInt(String msg) {
        int num = 0;
        try {
            System.out.println(msg);
            num = (new Scanner(System.in)).nextInt();
        } catch (InputMismatchException e) {
            System.out.println("Invalid value!");
            num = readInt(msg);
        } 
        return num;
    }

回答by jerjer

package nzt.nazakthul.app;

import java.util.*;

public class NztMainApp {

    public static void main(String[] args) {
    ReadNumber readObj = new ReadNumber();
    readObj.readNumber();
    }

}

class ReadNumber {
int no;

    int readNumber() {
    Scanner number = new Scanner(System.in);
    int no=0;
    boolean b=true;
    do {

        try {
            System.out.print("Enter a number:\t");
            no = number.nextInt();
        } catch (InputMismatchException e) {
            System.out.println("No Number");
            //e.printStackTrace();

            b=false;
        }

    }

    while (b);
    return no;

    }

}

Personally i use BufferedReader and InputStreamReader to read String and check if is a number or not, but with scanner is less code. The code is checked and run ok.

我个人使用 BufferedReader 和 InputStreamReader 来读取字符串并检查是否为数字,但使用扫描仪的代码较少。检查代码并运行正常。