为什么我的 while(Scanner.hasNext()) 循环永远不会退出?

Why does my while(Scanner.hasNext()) loop never exit?

提问人:eric_codes 提问时间:10/26/2023 最后编辑:eric_codes 更新时间:11/4/2023 访问量:115

问:

我正在学习 Java 并构建一个战舰游戏作为学习练习。我创建了一个方法来接收来自用户的一组坐标,该坐标以两个整数的形式输入,并用空格分隔。我已经验证了两个整数是否被正确读取,但随后程序继续从键盘接收输入,并且永远不会退出 while 循环。因此,该方法从不返回一组坐标。我已经搜索并阅读了很多关于使用 Scanner 的信息,但我看不出我的代码有什么问题。你能告诉我我做错了什么吗?

传入的扫描程序是 。Scanner(System.in)

public static int[] getCoordinates(Scanner input, String prompt) {
    int[] coordinates = new int[2];
    boolean invalid = false;

    do {
        System.out.println(prompt + ":");
        int index = 0;
        while (input.hasNext()) {
            if (input.hasNextInt() && index < 2) {
                coordinates[index] = input.nextInt();
                index++;
            } else {
                input.next();
            }
        }
            
        if (coordinates[0] < 0 || coordinates[0] > 4 || coordinates[1] < 0 || coordinates[1] > 4) {
            System.out.println("Invalid coordinates. Choose different coordinates.");
            invalid = true;
        }
    } while (invalid);
    
    return coordinates;
}

我希望用户输入两个整数,然后按回车键,循环将退出并继续执行该方法的其余部分。while(input.hasNext())

更新:我通过简单地执行以下操作来获得基本功能。我不确定这是否可靠,但现在可以。

int index = 0;
while (index < 2) {
    if (input.hasNextInt()) {
        coordinates[index] = input.nextInt();
        index++;
    }
}

这也很好用。感谢@k314159!

String[] answer = input.nextLine().split(" ");
if (answer.length >= 2) {
    coordinates[0] = Integer.parseInt(answer[0]);
    coordinates[1] = Integer.parseInt(answer[1]);
}
java.util.scanner 无限循环

评论

3赞 Mark Rotteveel 10/26/2023
如果这是一个包装(或例如网络套接字),那么只要它没有被关闭(这将使它到达流结束/文件结束),它就会阻止等待更多输入。ScannerSystem.in
1赞 Anonymous 10/26/2023
你从哪个来源阅读?一个终端/提示符,一个文件,s 套接字......?在第一种情况下,您无法区分用户已经键入的输入和输入,他们只会在方法返回后键入。
1赞 eric_codes 10/26/2023
输入来自 Scanner(System.in)。
1赞 k314159 10/27/2023
输入一整行 (),然后从行 () 中获取前两个标记,然后丢弃该行上的任何其他标记。input.nextLine()line.split()
1赞 Anonymous 10/27/2023
对于我们的建议,您应该首先更准确、更清晰、更全面地解释您想要获得的东西。但是,有很多读取和验证用户输入的示例,因此您可能会找到一些有用的东西。如果您只想删除同一行的其余部分(您没有告诉我们),就像 .input.nextLine();

答:

0赞 Owais Yosuf 10/27/2023 #1

原始循环永远不会退出的原因是因为它等待输入流 () 被关闭,这通常发生在程序终止时。它不会仅仅因为用户按 Enter 键而退出。while (input.hasNext())System.in

如果要继续使用 while (input.hasNext()) 循环,并且仍然允许用户输入后跟 Enter 的值,则可以像这样修改代码:

public static int[] getCoordinates(Scanner input, String prompt) {
    int[] coordinates = new int[2];
    boolean invalid = false;

    do {
        System.out.println(prompt + ":");
        int index = 0;
        while (index < 2) {
            if (input.hasNextInt()) {
                coordinates[index] = input.nextInt();
                index++;
            } else {
                input.next(); // Consume the non-integer token
            }
        }

        if (coordinates[0] < 0 || coordinates[0] > 4 || coordinates[1] < 0 || coordinates[1] > 4) {
            System.out.println("Invalid coordinates. Choose different coordinates.");
            invalid = true;
        } else {
            invalid = false;
        }
    } while (invalid);

    return coordinates;
}

评论

0赞 eric_codes 10/27/2023
这确实有效,但它不使用 .尽管在网上看到了很多这样的例子,但我根本无法让它发挥作用。while(input.hasNext())
2赞 Reilas 10/27/2023 #2

“为什么我的while(Scanner.hasNext())循环永远不会退出?..."

它正在等待更多的输入。
Java 中,这有时被称为“阻塞”。

"...我希望用户输入两个整数,然后按回车键,while(input.hasNext()) 循环将退出并继续执行该方法的其余部分。..."

只需调用 nextInt 方法两次即可。

int[] coordinates;
boolean invalid;

do {
    System.out.println(prompt + ":");
    coordinates = new int[] { input.nextInt(), input.nextInt() };

    invalid = false;
    if (coordinates[0] < 0 || coordinates[0] > 4 || coordinates[1] < 0 || coordinates[1] > 4) {
        System.out.println("Invalid coordinates. Choose different coordinates.");
        invalid = true;
    }
} while (invalid);

return coordinates;

更好的方法是在将值添加到坐标时检查值。

int[] coordinates = new int[2];
boolean invalid = true;

do {
    System.out.println(prompt + ":");
    switch (coordinates[0] = input.nextInt()) {
        case 1, 2, 3, 4 -> {
            switch (coordinates[1] = input.nextInt()) {
                case 1, 2, 3, 4 -> invalid = false;
            }
        }
    }
    if (invalid) {
        System.out.println("Invalid coordinates. Choose different coordinates.");
        input.nextLine();
    }
} while (invalid);

return coordinates;

或者,最好使用 Scanner#nextnextLine 方法以及 Integer#parseInt 方法计算输入。

int a = 0, b = 0;
boolean exit = false;
do {
    System.out.println(prompt + ":");
    try {
        a = Integer.parseInt(input.next());
        b = Integer.parseInt(input.next());
        if (Math.min(a, b) < 0 || Math.max(a, b) > 4) throw new Exception();
        exit = true;
    } catch (Exception e) {
        System.out.println("Invalid coordinates. Choose different coordinates.");
        input.nextLine();
    }
} while (!exit);
return new int[] { a, b };

或者,

int[] coordinates = null;
boolean exit = false;
do {
    System.out.println(prompt + ":");
    try {
        coordinates
            = input.tokens()
                   .limit(2)
                   .mapToInt(Integer::parseInt)
                   .peek(x -> {
                       if (x < 0 || x > 4)
                           throw new RuntimeException(); })
                   .toArray();
        exit = true;
    } catch (RuntimeException e) {
        System.out.println("Invalid coordinates. Choose different coordinates.");
        input.nextLine();
    }
} while (!exit);
return coordinates;