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

时间:2022-05-30 00:20:38

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!
...

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

5 个解决方案

#1


48  

As per the javadoc for 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 catch to consume the token, which is invalid and needs to be discarded.

这意味着如果下一个标记不是int,它会抛出InputMismatchException,但令牌仍然存在。因此,在循环的下一次迭代中,reader.nextInt()再次读取相同的标记并再次抛出异常。你需要的是用它。在catch中添加reader.next()以使用令牌,该令牌无效且需要被丢弃。

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

#2


0  

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.

通过这种方式,您可以使用一个获取输入的扫描仪和一个可以验证输入的扫描仪,这样您就不必担心如果输入正确的输入形式的读者关怀。

#3


0  

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

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

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();

在代码到达赋值循环= 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 :

要在做什么时终止这个,你需要用另一个合乎逻辑的东西保护你的做法,例如:

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

  3. Exit when EOF
  4. EOF时退出

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

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

#4


0  

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;
    }

#5


0  

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来读取String并检查是否是数字,但扫描器代码较少。检查代码并运行正常。

#1


48  

As per the javadoc for 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 catch to consume the token, which is invalid and needs to be discarded.

这意味着如果下一个标记不是int,它会抛出InputMismatchException,但令牌仍然存在。因此,在循环的下一次迭代中,reader.nextInt()再次读取相同的标记并再次抛出异常。你需要的是用它。在catch中添加reader.next()以使用令牌,该令牌无效且需要被丢弃。

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

#2


0  

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.

通过这种方式,您可以使用一个获取输入的扫描仪和一个可以验证输入的扫描仪,这样您就不必担心如果输入正确的输入形式的读者关怀。

#3


0  

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

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

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();

在代码到达赋值循环= 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 :

要在做什么时终止这个,你需要用另一个合乎逻辑的东西保护你的做法,例如:

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

  3. Exit when EOF
  4. EOF时退出

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

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

#4


0  

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;
    }

#5


0  

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来读取String并检查是否是数字,但扫描器代码较少。检查代码并运行正常。