Why is this Scanner assigning null to a variable?

2019-08-17 07:38发布

问题:

For a college assessment I'm having to use a Scanner called sc with a class-level scope, and the entirety of the program has to be contained in a single class. The main method calls a menu() method, which uses the Scanner and a for loop to call one of two methods in response to user input.

One of the two methods uses the Scanner to calculate the factorial of an input integer. Once the method is executed, the for loop in menu() continues. To avoid an InputMismatchException due to the user entering a float, I used try/catch. However when the program returns back to the menu() for loop the Scanner causes an InputMismatchException when assigning to choice. How can I get Scanner to prompt the user for input again? Apologies if I'm missing something obvious, this is the first programming language I've ever learned. This should be the stripped down compilable code:

package summativeassessment;

import java.util.InputMismatchException;
import java.util.Scanner;

public class SummativeAssessment {

    private static Scanner sc = new Scanner(System.in);

    public static void main(String[] args) {
        menu();
    }

    public static void menu(){
        String fName;
        String sName;

        System.out.print("Enter your first name: ");
        fName = sc.next();
        System.out.print("Enter your last name: ");
        sName = sc.next();

        try{
            for(int choice = 1; choice!=0;){
              System.out.print("Option 1 to generate username. Option 2 to calculate factorial. Press 0 to quit: ");
              choice = sc.nextInt();
              switch(choice){
                  case 2:
                      System.out.println(fName+" "+sName+", you have selected option 2");
                      numberFactorial();
                      break;
                  case 0:
                      break;
                  default:
                      System.out.println("Invalid option. Please try again.");
              }
            }
        } catch(InputMismatchException ex){
            String msg = ex.getMessage();
            System.out.println(msg);
        }
    }

    public static void numberFactorial(){
        System.out.print("Enter a number: ");
        try{
            int numIn = sc.nextInt();
            long result = numIn;
            if(numIn>0){

                for(int factor = 1; factor<numIn; factor++){
                    result *= factor;
                    if(factor==numIn-1){
                        System.out.println("The factorial is "+result);
                    }
                }
            }
            else{
                System.out.println("Enter a positive integer greater than 0");
            }
        }
        catch(InputMismatchException ex){
            System.out.println("Input invalid");
        }
    }
}

回答1:

I debugged your code and got this result:

If you enter a float as input you trigger the InputMismatchException but there is still something in your buffer. So the next time sc.nextInt() is called, it won't wait until you input a value because something is in the buffer already, so it takes the next value out of the buffer and tries to interpret is as an integer. However, it fails to do so, because it is not an integer, so an InputMismatchException is raised again and caught in your menu's catch, now leading to the exit of the program.

The solution is to draw whatever is left in the buffer after the exception was raised the first time.

So the working code will contain a buffer clearing sc.next() inside the exception:

    public static void numberFactorial(){
    System.out.print("Enter a number: ");
    try{
        int numIn = sc.nextInt();
        long result = numIn;
        if(numIn>0){

            for(int factor = 1; factor<numIn; factor++){
                result *= factor;
                if(factor==numIn-1){
                    System.out.println("The factorial is "+result);
                }
            }
        }
        else{
            System.out.println("Enter a positive integer greater than 0");
        }
    }
    catch(InputMismatchException ex){
        System.out.println("Input invalid");
        sc.next();
    }
}