0

My InputMismatchException isn't working, as when I put in something like a double into the input, instead of the exception output message, it gives me:

Exception in thread "main" java.lang.NumberFormatException: For input string: "1.2"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at reviewGUI.NChooseR.main(NChooseR.java:32)

I've noticed a lot of other InputMismatchExceptions use scanners instead of DataInputStream, would I have to change it to that format in order for it to work? Here's part of my code:

    public static void main(String[] args) throws IOException {
    DataInputStream input = new DataInputStream (System.in);
    
    int numChosenObj = -1;
    int numTotalObj=-1;
    
    
    try
    {
    System.out.print("Enter the number of objects to choose: ");
    numChosenObj = Integer.parseInt(input.readLine());
    }
    catch(InputMismatchException e)
    {
        System.out.println("You must input an integer value.");
        
    }
    
    try
    {
    System.out.print("Enter the total number of objects to choose from: ");
    numTotalObj = Integer.parseInt(input.readLine());
    }
    catch(InputMismatchException e)
    {
        System.out.println("You must input an integer value.");
        
    }
    
    int difference = numTotalObj-numChosenObj;
    
    int rFact = factorial(numChosenObj);
    int nFact = factorial(numTotalObj);
    int differenceFact = factorial(numTotalObj-numChosenObj);
    
    int totalWaysToChoose = nFact/(rFact*differenceFact);
    System.out.println();
    System.out.println("There are " + totalWaysToChoose + " ways to choose " + numChosenObj + " objects from " + numTotalObj + " total number of objects.");
    
    
    
}
gino
  • 41
  • 5
  • Unrelated, but `readLine` is deprecated. – Federico klez Culloca Mar 30 '21 at 13:44
  • You're just catching the wrong exception. As per the message what is thrown is a `NumberFormatException`, not an `InputMismatchException`. – Federico klez Culloca Mar 30 '21 at 13:47
  • @FedericoklezCulloca is there a way to fix that? I don't think I've ever come across that before – gino Mar 30 '21 at 13:48
  • There's nothing to fix apart from catching the correct exception. – Federico klez Culloca Mar 30 '21 at 13:49
  • @FedericoklezCulloca Oh okay thank you. So I'm sort of confused because I thought that NumberFormatException would only catch if a string was inputted? But I also would like to catch if a double is inputted. – gino Mar 30 '21 at 13:51
  • It's [`parseInt`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Integer.html#parseInt(java.lang.String)) that's throwing the exception. In the documentation it says it throws `NumberFormatException` *"if the string does not contain a parsable integer"* – Federico klez Culloca Mar 30 '21 at 13:53

1 Answers1

1

The base problem is that input.readLine() won't throw InputMismatch, as there is a line there, you can't not have one (if there is no line, the readLine() method will just wait until there is, or return null if the stream is closed). InputMismatch only occurs if you ask for some specific datatype, such as 'an int, please'.

Integer.parseInt, if the passed in string isn't an int, will throw NumberFormatException and not InputMismatchException.

The direct fix is to catch NumberFormatException instead. But you've made this code vastly more complicated than it needs to be.

Scanner s = new Scanner(System.in);
s.useDelimiter("\\R"); // the enter key delimits.

System.out.print("Enter the number of objects to choose: ");
numChosenObj = s.nextInt();

System.out.println("Enter your name: ");
name = s.next();

NB: Don't ever call scanner.nextLine. It is 'broken' (it does what the api says it does, but it's not what you think). To read a line, call .next(). This works due to setting the delimiter properly. Forget about DataInputStream.

Now if you want to print something customized, I'd make a method instead:


public int askForInt(Scanner s, String prompt) {
  while (true) {
    try {
      System.out.print(prompt);
      return s.nextInt();
    } catch (InputMismatchException e) {
      System.out.println("An integer number is required.");
    }
  }
}

now you can call askForInt(s, "Enter the number of objects to choose: ") and this will ask, and keep asking until the user enters something.

Anytime you have the tendency to copy/paste code, you should always be thinking: Hmmm, is there an obvious singular purpose to the code I am copying? If the answer is yes, make a method.

class App {
  public static void main(String[] args) throws Exception {
    new App().go(); // your main should always be a one-liner, really.
  }

  public void go() throws Exception {
    Scanner s = new Scanner(System.in);
    s.useDelimiter("\\R");
    
    int numChosenObj = askInt(s, "Enter the number of objects to choose: ");
    int numTotalObj = askInt(s, "Enter the total number of objects to choose from: ");
    
    int difference = numTotalObj-numChosenObj;
    
    int rFact = factorial(numChosenObj);
    int nFact = factorial(numTotalObj);
    int differenceFact = factorial(numTotalObj-numChosenObj);
    
    int totalWaysToChoose = nFact/(rFact*differenceFact);
    System.out.println();
    System.out.println("There are " + totalWaysToChoose + " ways to choose " + numChosenObj + " objects from " + numTotalObj + " total number of objects.");
  }

  private int askInt(Scanner s, String prompt) {
    while (true) {
      System.out.print(prompt);
      try {
        return s.nextInt();    
      } catch (InputMismatchException e) {
        System.out.println("An integer number is required.");
      }
    }
  }
} 

Looks a lot cleaner, no?

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72