nextInt() caused an infinit loop

Viewed 263

My expectation:

If the user types an Int which is not in the right range, the program will give him another chance until the user gives the right type.

So, I need a while block. But I got an infinite loop.

My code:

import java.util.NoSuchElementException;
import java.util.Scanner;

public class TestInput {
    public static void main (String[] args) {
        boolean keepRunning = true;
        while (keepRunning) {
            try {
                System.out.println("Start --- ");
                Integer selection = inputSelection();
                //Integer selection = Integer.parseInt(selectionString);
                String email;
                switch (selection) {
                    case 1:
                        // inputDate();
                        System.out.println("Do 1");

                        break;
                    case 2:
                        //inputEmail();
                        System.out.println("Do 2");
                        break;
                    case 3:
                        //inputName();
                        System.out.println("Do 3");

                        break;
                    case 4:
                        // Exit
                        keepRunning = false;
                        break;
                    default:
                        System.out.println("Please enter a number 1 to 4: ");
                        break;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public static Integer inputSelection () {
        Integer selection = 0;
        try (Scanner scanner = new Scanner(System.in)) {
            if (scanner.hasNext()) {
                selection = scanner.nextInt();  // reads only one int. does not finish the line.
                scanner.nextLine(); // consume '\n' to finish the line
            }
        } catch (NoSuchElementException ex) {
            throw ex;
        }
        return selection;
    }
}

DOCs I read:

Resetting a .nextLine() Scanner

Using Scanner.nextLine() after Scanner.nextInt()

Scanner error with nextInt()

Scanner is skipping nextLine() after using next() or nextFoo()?

How to use java.util.Scanner to correctly read user input from System.in and act on it?

The Scanner Class String formatting in Java Scanner class

Java Scanner doesn't wait for user input

Java String Scanner input does not wait for info, moves directly to next statement. How to wait for info?

String formatting in Java Scanner class

Scanner.html#nextInt() javase 7

Scanner.html#nextInt() Javase 14

Those answers do not work for me. I still get an infinite loop. Any advice? Thank you.

EDIT

First I enter an invalid selection, say 8, nextInt() will wait for input. The program will allow to enter an integer again. But in the second round, nextInt() does not wait for input.

If I tried this:

       try (Scanner scanner = new Scanner(System.in)) {
            selection = scanner.nextInt();  // reads only one int. does not finish the line.
            scanner.nextLine(); // consume '\n' to finish the line
        } catch (NoSuchElementException ex) {
            throw ex;
        }

The scanner.nextLine() will not being executed after the first round. It back to try (Scanner scanner = new Scanner(System.in)) to close the Scanner. Then I got NoSuchElementException.

EDIT

The main problem is nextInt() is not waiting for input in the second round. There should be a way to block the program waiting for input, before the scanner being closed. javase 7 oracle doc saying:

public boolean hasNext()

Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input.

EDIT

ENV: IntelliJ IDEA 2021.2, jdk 14.0.2

4 Answers

try to set keepRunning on false, if it so happens, that you reach in to a case state.

In Java, the break statement breaks out of the current iteration to the next enclosing level of control. It seems you expect the break in the switch to break you out of the while loop, but it only gets you out of the current case.

Try changing the keepRunning flag within any of the cases representing a success condition, rather than the failure condition. keepRunning should be changed to false when you get good input, not bad input. You only want to continue asking when you get bad input, correct?

I maybe don't quite understand what you mean.But I think writing it this way works fine.I just tried it again, so that I don't get stuck in an infinite loop.

public static void main(String[] args) {
        boolean keepRunning = true;
        while (keepRunning) {
            try {
                System.out.println("Start --- ");
                Integer selection = inputSelection();
                //Integer selection = Integer.parseInt(selectionString);
                String email;
                switch (selection) {
                    case 1:
                        // inputDate();
                        System.out.println("Do 1");
                        break;
                    case 2:
                        //inputEmail();
                        System.out.println("Do 2");
                        break;
                    case 3:
                        //inputName();
                        System.out.println("Do 3");

                        break;
                    case 5:
                        // Exit
                        keepRunning = false;
                        break;
                    default:
                        System.out.println("Please enter a number between 1 and 3: ");
                        break;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public static Integer inputSelection() {
        Integer selection = 0;
        Scanner scanner = new Scanner(System.in);
        try {
            if (scanner.hasNext()) {
                selection = scanner.nextInt();
                scanner.nextLine();
            }
        } catch (NoSuchElementException ex) {
            throw ex;
        }
        return selection;
    }

scanner.hasNext() is returning false, which causes it to return 0, which is out of bounds. This is because the Scanner object is being closed, therefore closing System.in. Check the comment for credit.

If you replace the if statement in inputSelection with the following, it prints e and infinite loops.

if (scanner.hasNext()) {
    selection = scanner.nextInt();
    scanner.nextLine();
} else {
    System.out.println("e");
    while (true) {}
}
Related