如何在输入错误类型时防止扫描仪抛出异常?

16

这是一些示例代码:

import java.util.Scanner;
class In
{
    public static void main (String[]arg) 
    {
    Scanner in = new Scanner (System.in) ;
    System.out.println ("how many are invading?") ;
    int a = in.nextInt() ; 
    System.out.println (a) ; 
    } 
}

如果我运行程序并输入一个像4这样的int,那么一切都很好。

另一方面,如果我回答太多了,它不会笑我的有趣的笑话。相反,我得到了以下结果(如预期):

Exception in thread "main" java.util.InputMismatchException
    at java.util.Scanner.throwFor(Scanner.java:819)
    at java.util.Scanner.next(Scanner.java:1431)
    at java.util.Scanner.nextInt(Scanner.java:2040)
    at java.util.Scanner.nextInt(Scanner.java:2000)
    at In.main(In.java:9)
有没有办法让它忽略不是整数的条目或重新提示“有多少人在入侵?”我想知道如何同时实现这两个功能。
3个回答

22
你可以使用Scanner中的许多hasNext*方法进行预验证。
    if (in.hasNextInt()) {
        int a = in.nextInt() ; 
        System.out.println(a);
    } else {
        System.out.println("Sorry, couldn't understand you!");
    }

这样做可以防止抛出InputMismatchException异常,因为在读取输入之前,您总是确保它将会匹配。


java.util.Scanner API

  • boolean hasNextInt(): 如果此扫描器输入中的下一个标记可以解释为使用 nextInt() 方法在默认基数中表示的 int 值,则返回 true扫描器不会超过任何输入。

  • String nextLine(): 使此扫描器前进到当前行的末尾,并返回被跳过的输入。

请注意加粗的部分。 hasNextInt() 不会超过任何输入。如果它返回 true,则可以通过调用 nextInt() 来推进扫描器,它将不会抛出 InputMismatchException

如果它返回 false,那么您需要跳过“垃圾”。最简单的方法是只需调用 nextLine(),可能需要两次,但至少一次。

为什么您可能需要调用两次nextLine()是因为输入可能如下所示:

42[enter]
too many![enter]
0[enter]

假设扫描器在输入的开头。
  • 如果 hasNextInt() 为 true,则 nextInt() 返回 42;此时扫描器位于第一个 [enter] 的前面。
  • 如果 hasNextInt() 为 false,则 nextLine() 返回一个空字符串,第二个 nextLine() 返回 "too many!";此时扫描器位于第二个 [enter] 的后面。
  • 如果 hasNextInt() 为 true,则 nextInt() 返回 0;此时扫描器位于第三个 [enter] 的前面。

下面是将一些内容组合在一起的示例。您可以通过实验来学习 Scanner 的工作原理。
        Scanner in = new Scanner (System.in) ;
        System.out.println("Age?");
        while (!in.hasNextInt()) {
            in.next(); // What happens if you use nextLine() instead?
        }
        int age = in.nextInt();
        in.nextLine(); // What happens if you remove this statement?
        
        System.out.println("Name?");
        String name = in.nextLine();
        
        System.out.format("[%s] is %d years old", name, age);

假设输入为:

He is probably close to 100 now...[enter]
Elvis, of course[enter]

然后输出的最后一行是:
[Elvis, of course] is 100 years old

这看起来很有前途。您能否明确解释一下 hasNextInt() 的作用? - David

2
一般来说,我非常不喜欢使用同一个库调用来进行读取和解析。语言库似乎非常缺乏灵活性,往往不能按照您的意愿进行操作。
从System.in中提取数据的第一步不应该失败,因此请将其读入变量作为字符串,然后将该字符串变量转换为整数。如果转换失败,那就打印错误并继续执行。
当您使用能够抛出异常的流进行包装时,整个混乱状态会变得有点令人困惑。

1

当应用程序出现错误时,让它抛出一个错误总是有益的,而不是想方设法避免错误发生。

其中一种替代方法是将代码包装在 try {...} catch {...}块中以捕获 InputMismatchException。您还可能希望将代码包装在 while 循环内,让 Scanner 持续提示,直到满足特定条件为止。


你应该将"found=true;"移到try语句的顶部。现在它总是为真。 - Oskar Kjellin
我省略了我的例子,感觉不太对。我只是想传达主要观点:你应该捕获被抛出的错误,而不是绕过它们,并提供了“重新提示”的技巧。无论如何,还是谢谢Kurresmack。 - Anthony Forloney
一个 try catch 块是如何工作的?我以前从未使用过。 - David
我正在使用手机,我会尽力而为。try { // 在此处编写代码 } catch(InputMismatchException e) { // 捕获错误格式 } - Anthony Forloney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接