2

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

Nick Dong
  • 3,638
  • 8
  • 47
  • 84
  • Have you tried throwing away the next input by using `scanner.next()`? – cs1349459 Mar 29 '22 at 16:36
  • 1
    The `Scanner` is being closed automatically since in a try-with-resource, that is also closing `System.in` so on second call, `hasNext` will always return false since the standard input it closed (bad practice IMHO) - remove the try-with-resource and open the `Scanner` only once in `main` – user16320675 Mar 29 '22 at 17:14
  • 1
    It seems weird to try using a new Scanner for every line. I found a couple tutorials in line with my expectation of how java input works, but Scanners just don't seem to wait for input today. – clwhisk Mar 30 '22 at 03:05
  • It may depend on where you're running it. Of the example at https://stackoverflow.com/questions/30249324/how-to-get-java-to-wait-for-user-input : A LeetCode playground fails while IntelliJ IDEA behaves as expected. – clwhisk Mar 30 '22 at 03:26
  • In this type of program we often include a counter so as to request the input a few times, 5 for example, and then close the program (or ask the user if they want to quit). We can event append "try 2 / 5" etc to the request for information. –  Mar 30 '22 at 05:24
  • `public static Integer inputSelection () { Integer selection = 0; try { Scanner scanner = new Scanner(System.in); selection = scanner.nextInt(); scanner.nextLine(); } catch (NoSuchElementException ex) { throw ex; } return selection; }` This works. `try(Scanner scanner = new Scanner(System.in)` and `scanner.close()` seems close the scanner instead of waiting input, when `nextInt()` or `nextLine()` failed . But I dont know, why. – Nick Dong Mar 31 '22 at 16:46

4 Answers4

0

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

0

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?

MarsAtomic
  • 10,436
  • 5
  • 35
  • 56
0

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;
    }
Shawn Gao
  • 1
  • 1
  • if you type `1` or `3` it infinitely prints `Start --- Please enter a number between 1 and 3` – cs1349459 Mar 29 '22 at 17:03
  • I ditched the "inputSelection" method here. – Shawn Gao Mar 29 '22 at 17:03
  • I didn't get stuck in an infinite loop after entering "1" and "3" – Shawn Gao Mar 29 '22 at 17:04
  • Oh, I was talking about the original problem. – cs1349459 Mar 29 '22 at 17:04
  • The original question Entering any number will get into an infinite loop.Of course, except for "5". – Shawn Gao Mar 29 '22 at 17:08
  • I just want to put all input logic into a method, say, inputSelect(), inputEmail(), inputDate(). @ShawnGao So that they can be wrapped in a class, say util class. – Nick Dong Mar 30 '22 at 02:39
  • Maybe, **"try(){}"** will cause the resource in parentheses to be automatically closed when leaving the **"try"** section. – Shawn Gao Mar 30 '22 at 04:09
  • Now, I can sure that `try()` can close scanner automatically following the [DOC](https://web.eecs.utk.edu/~bvanderz/cs365/examples/datacheck.html#:~:text=When%20you%20have%20finished%20using%20a%20Scanner%2C%20such,will%20have%20a%20memory%20leak%20in%20your%20program%3A). The problem is there should be a way to waiting input, before the scanner being closed. – Nick Dong Mar 30 '22 at 05:15
0

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) {}
}
cs1349459
  • 911
  • 9
  • 27
  • 1
    "I do not know why" -> because the `Scanner` is being closed, closing `System.in` – user16320675 Mar 29 '22 at 17:15
  • [Scanner.html#hasNext()](https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNext()) should wait for input, right? So that `nextInt()` could get the int. – Nick Dong Mar 30 '22 at 02:37
  • So There should be a way that the scanner waiting for input before it is being closed. – Nick Dong Mar 30 '22 at 05:16
  • `if(!scanner.hasNext())` gives infinite loop either. The problem still exists. `hasNext()` not block for waiting input. But [Oracle docs javase 7](https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNext()) says : `This method may block while waiting for input to scan.` – Nick Dong Mar 30 '22 at 05:30
  • [Oracle Doc javase 14 hasNext()](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Scanner.html#hasNext()). `This method may block while waiting for input to scan.` – Nick Dong Mar 30 '22 at 06:05