Java Scanner’s unexpected behavior following nextInt or nextDouble call
Scanner is a utility class that provides methods to read command-line input. It is a very useful class, but you need to be aware of its unexpected behavior while reading numeric inputs.
Consider the following example.
try (Scanner in = new Scanner(System.in)) { System.out.print("Enter Item ID: "); String itemID = in.nextLine(); System.out.print("Enter item price: "); double price = in.nextDouble(); System.out.println("Price of item " + itemID + " is $" + price); } catch (Exception e) { e.printStackTrace(); }
As expected the output from this code will look something like:
Enter Item ID: XY1234 Enter item price: 99.99 Price of item XY1234 is $99.99
Everything worked as expected. The program prompted the user to enter an item ID and price. It read the values and then displayed them on console correctly. Now, let’s see what happens if we ask the user to enter the price first followed by item ID.
try (Scanner in = new Scanner(System.in)) { System.out.print("Enter item price: "); double price = in.nextDouble(); System.out.print("Enter Item ID: "); String itemID = in.nextLine(); System.out.println("Price of item " + itemID + " is $ " + price); } catch (Exception e) { e.printStackTrace(); }
This version resulted in a bizarre output.
Enter item price: 85.79 Enter Item ID: Price of item is $ 85.79
What happened here? The program didn’t wait for the user to enter item ID. After prompting the user to enter the item ID, it right away printed the final message with a blank item ID.
Understanding Scanner.getDouble() and Scanner.getInt()
What caused this behavior? To solve this mystery we have to understand how Scanner.getDouble() or Scanner.getInt() methods work. Basically, Scanner’s get methods read the input character by character instead of reading the entire line at once. getDouble and getInt methods read input until they reach a non-numeric character. In this example, the user entered 99.99 and then hit enter (“\n“). So the character sequence would be 99.99\n. The method getDouble() reads the characters up to the last “9”. Since the next character is a non-numeric value (\n), the method stopped and returned the value 85.79 to be saved in the price variable. That left \n character in the buffer. Next, the program called nextLine() method. This method reads the input until it reaches the newline character (\n). Since the input stream had the \n character from the last input, the method reads it and returns immediately without allowing the user to input the ID.
To overcome this issue you have two options.
- Always call nextLine() method after calling nextInt() or nextDouble() method to consume line feed.
- Always read command line input using nextLine() method and then converts numeric values from String to appropriate numeric type.
try (Scanner in = new Scanner(System.in)) { System.out.print("Enter item price: "); double price = in.nextDouble(); in.nextLine(); System.out.print("Enter Item ID: "); String itemID = in.nextLine(); System.out.println("Price of item " + itemID + " is $ " + price); } catch (Exception e) { e.printStackTrace(); }
Which gives correct results.
Enter item price: 85.79 Enter Item ID: XY1234 Price of item XY1234 is $ 85.79
try (Scanner in = new Scanner(System.in)) { System.out.print("Enter item price: "); String priceStr = in.nextLine(); double price = Double.valueOf(priceStr); System.out.print("Enter Item ID: "); String itemID = in.nextLine(); System.out.println("Price of item " + itemID + " is $ " + price); } catch (Exception e) { e.printStackTrace(); }
Enter item price: 85.99 Enter Item ID: AB2314 Price of item AB2314 is $ 85.99
Personally, I prefer the first approach.