Question

I don't understand the logic to this. If I run this code and enter a non-int such as the letter f, I get stuck in an infinite loop outputting the two println's and I am not given another chance to input an int to the scanner...it just keeps spitting out words to the console.

public static void main(String[] args) {

    Scanner scan = new Scanner(System.in);//<<<<<SCANNER HERE
    int opponents = 0;
    boolean opponentsCreated = false;
    while(opponentsCreated == false)
    {
        try
        {
            System.out.print("How many players: ");
            int tempOpponents = scan.nextInt();
            if(tempOpponents > 0)
            {
                opponents = tempOpponents;
                opponentsCreated = true;
            }   
        }
        catch(InputMismatchException notAValidInt)
        {
            System.out.println("Not valid - must be a number greater than 0 ");
        }   
    }
}

But if I simply change the Scanner to be declared inside the while loop, all of a sudden the program works as expected:

public static void main(String[] args) {

    int opponents = 0;
    boolean opponentsCreated = false;
    while(opponentsCreated == false)
    {
        Scanner scan = new Scanner(System.in);//<<<<<SCANNER HERE
        try
        {
            System.out.print("How many players: ");
            int tempOpponents = scan.nextInt();
            if(tempOpponents > 0)
            {
                opponents = tempOpponents;
                opponentsCreated = true;
            }   
        }
        catch(InputMismatchException notAValidInt)
        {
            System.out.println("Not valid - must be a number greater than 0 ");
        }   
    }
}

I honestly just sat here for 2 hours trying to figure out what the heck was wrong with my program only to find out it was a matter of where I declared my Scanner even though in both versions of the code the Scanner was not out of scope. So now I'm really curious why it works this way

Was it helpful?

Solution

Adding on to @HovercraftFullOfEels answer:

The root cause is, the scanner position does not move in case of the said exception. So scanner keeps reating same bad input again and again. Quoting JavaDoc

If the translation is successful, the scanner advances past the input that matched.

catch(InputMismatchException notAValidInt)
{
    scan.reset();
    System.out.println("Not valid - must be a number greater than 0 "); 
    //position is still 0
    scan.next(); //position is now 1
}

To visualize:

Input:                  f______________
Scanner position:       ^______________

InputMismatchException  ^______________
scan.next()             _^_____________ 

Relevant source (look at the source comment):

try {
            String s = next(integerPattern());
            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                s = processIntegerToken(s);
            return Integer.parseInt(s, radix);
        } catch (NumberFormatException nfe) {
            position = matcher.start(); // don't skip bad token   
            throw new InputMismatchException(nfe.getMessage());
        }

OTHER TIPS

One possible problem is that you may be leaving the end of line token hanging when an excpetion occurs. If you handle this by making sure to swallow the end of line token when needed, you are likely OK. For example:

public static void main(String[] args) {

  Scanner scan = new Scanner(System.in);// <<<<<SCANNER HERE
  int opponents = 0;
  boolean opponentsCreated = false;
  while (opponentsCreated == false) {
     try {
        System.out.print("How many players: ");
        int tempOpponents = scan.nextInt();

        // line below corrected! 
        scan.nextLine();  // *** this might not be a bad idea either ***

        if (tempOpponents > 0) {
           opponents = tempOpponents;
           opponentsCreated = true;
        }
     } catch (InputMismatchException notAValidInt) {
        System.out.println("Not valid - must be a number greater than 0 ");
        scan.nextLine();  // ****** this is what you need here *****
     }
  }
}

Nice question, by the way!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top