Search code examples
javaexceptioninputmismatchexception

InputMismatchException crashes program after being caught


Introduction

I am having a problem catching an InputMismatchException. I have read all of the threads on this site that appear on the first page when I search for InputMismatchException already. I found the answer to one of my questions while reading those threads; that answer taught me I had to add import java.util.InputMismatchException; in my import statements. However I'm having a different issue that I can't find in any solution to. The closest other question is this one. I think he was having the same issue as me, but that solution did not work for me.

My Issue

I'm making a class that demonstrates a ProductionWorker datatype that I made. I want to test all of the inputs to be sure that they are valid inputs that can be manipulated as expected. I'm trying to get a Double input for rate of pay, and I want to be asked to attempt inputting again if the input is wrong; say I accidentally input "gary" instead of my rate of pay. I figured a try-catch-finally would work but after entering the catch block I still get the InputMismatchException...

Console output

run:
What is your name: gary
Please enter employee number: 88-m
Incorrect employee ID, please check it and try again.
Enter employee number: 888-m
Please enter hire date as "MM/DD/YYYY": 07/14/1994
Please enter shift (1 for day shift, 2 for night shift.: 2
Please enter rate of pay: $h
Rate of pay can only be digits.
Exception in thread "main" java.util.InputMismatchException
Examples: 30.00; 22.10; 7.25; 10.00
    at java.util.Scanner.throwFor(Scanner.java:864)
Please enter rate of pay: $ at java.util.Scanner.next(Scanner.java:1485)
    at java.util.Scanner.nextDouble(Scanner.java:2413)
    at programmingchallengeq1.ProgrammingChallengeQ1.main(ProgrammingChallengeQ1.java:69)
Picked up _JAVA_OPTIONS: -Xmx512m
C:\Users\nikru\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 15 seconds)

It looks to me like I make it into the catch block since that print statement is showing in the console, and I thought if I make it to the catch block the exception couldn't crash the program. I don't know what I'm doing wrong...

Code

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package programmingchallengeq1;

import java.util.Scanner;
import java.util.regex.*;
import java.util.InputMismatchException;

public class ProgrammingChallengeQ1 {

    public static void main(String[] args) 
    {
        Scanner kb = new Scanner(System.in);
        final int SHIFT_LENGTH = 12;

        ProductionWorker workman = new ProductionWorker();
        System.out.print("What is your name: ");
        workman.set_name(kb.nextLine());
        System.out.print("Please enter employee number: ");
        // ask user for id and save it to workman
        workman.set_id(kb.nextLine());

        // while loop ensures that employee num matches specific format
        while (check_id(workman) == false)
        {
            System.out.print("Incorrect employee ID, please check it and" +
                    " try again.\n" + "Enter employee number: ");
            workman.set_id(kb.nextLine());
        }

        System.out.print("Please enter hire date as \"MM/DD/YYYY\": ");
        // ask user for date of hire and save it to workman
        workman.set_hire_date(kb.nextLine());
        // attempt to ensure a valid date was input with while loop
        while(check_date(workman) == false)
        {
            System.out.println("Date not recognized, please check date" +
                    " and try again.\n" + "Enter hire date as \"MM/DD/YYY\": ");
            workman.set_hire_date(kb.nextLine());
        }
        System.out.print("Please enter shift (1 for day shift, 2 for night"+
                " shift.: ");
        workman.set_shift(kb.nextInt());
        // the while loop checks if a correct value is stored for shift
        while(workman.get_shift() != 1 && workman.get_shift() != 2)
        {
            System.out.print("Unrecognized shift. Please enter a 1 for" +
                    " day shift, or 2 for night shift: ");
            workman.set_shift(kb.nextInt());
        }
        System.out.print("Please enter rate of pay: $");
        // attempt to ensure a valid rate of pay is input with try-catch
        // boolean is the exit condition for while loop, which only breaks
        // if the input is valid
        boolean valid_input = false;
        while (valid_input != true)
        {
            try
            {
                workman.set_pay_rate(kb.nextDouble());
                valid_input = true;
            }
            catch(InputMismatchException ex)
            {
                //System.out.println(ex.getMessage());
                System.out.print("Rate of pay can only be digits.\nExamples:" +
                    " 30.00; 22.10; 7.25; 10.00\nPlease enter rate of pay: $");
            }
            finally
            {
                workman.set_pay_rate(kb.nextDouble());
            }
        }

    }

    public static boolean check_id(ProductionWorker wrkr)
    {
        // creating a regex pattern to check against input employee ID
        // to avoid inputting error
        String id_format = "\\d{3}-[a-m]";
        Pattern id_pattern = Pattern.compile(id_format);
        // check id against compiled regex pattern and save to a bool
        Matcher id_matcher = id_pattern.matcher(wrkr.get_id());
        boolean id_matches = id_matcher.matches();
        return id_matches;
    }
    public static boolean check_date(ProductionWorker wrkr)
    {
        //same concept as in check_id()
        String date_format = "\\d{2}/\\d{2}/\\d{4}";
        Pattern date_pattern = Pattern.compile(date_format);
        Matcher date_matcher = date_pattern.matcher(wrkr.get_hire_date());
        boolean date_matches = date_matcher.matches();
        return date_matches;
    }
}

All help appreciated, thank you!


Solution

  • You're running nextDouble() in the finally block as well, so no matter what happens it will fail at this point. Basically the first call that fails does not consume the data so the second call doesn't wait for new user input, it immediately tries to consume the input already present and fails again.

    You have to explicitly consume the line to fix this issue:

    Scanner sc = new Scanner(System.in);
    try {
        sc.nextDouble();
    } catch (InputMismatchException e) {
        System.out.println("Oops, something went wrong...");
        sc.nextLine();
        sc.nextDouble();
    }
    

    I removed the finally block because I don't see why you would want to retry the operation when it succeeded on the first try.