I’m trying to write a Java program that asks the user to input a positive integer inside a while
loop. The loop should continue until valid input is provided.
I’ve tried using a try/catch
block to handle invalid inputs like strings, but I’m still running into issues. For example:
When the user enters a string, the program throws an InputMismatchException
and skips re-prompting the user.
I tried adding scanner.nextLine()
to clear the input buffer, but it didn’t work as expected.
Here’s the code I’ve written so far:
import java.util.Scanner;
public class InputExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int userInput = -1;
while (userInput < 0) {
try {
System.out.print("Enter a positive number: ");
userInput = scanner.nextInt(); // Crashes if invalid input is entered
} catch (InputMismatchException e) {
System.out.println("Invalid input. Please enter a valid number.");
scanner.nextLine(); // Attempt to clear the buffer, but it doesn't work
}
}
System.out.println("You entered: " + userInput);
scanner.close();
}
}
The issue:
When invalid input (like a string) is entered, the program skips re-prompting the user.
I suspect there’s an issue with how I’m clearing the input buffer using scanner.nextLine().
What I’ve tried:
Wrapping the scanner.nextInt() inside a try/catch block to catch the exception.
Using scanner.nextLine() after catching the exception to clear the input.
My question:
How can I properly handle invalid input in this scenario so that the program keeps re-prompting the user until a valid positive integer is provided?
Just as a suggestion, just use the Scanner#nextLine() method and compare the User's input with the String#matches() method and a small Regular Expression, for example:
import java.util.Scanner;
public class ScannerPromptDemo {
/* Don't close `System.in` unless you know it will never be
needed again during this application session otherwise
you will need to restart your application in order to
use it again. The JVM will automatically close this
stream and free resources when the application closes. */
private final Scanner userInput = new Scanner(System.in);
private final String ls = System.lineSeparator();
public static void main(String[] args) {
/* App started this way to avoid the need for
statics unless we really want them: */
new ScannerPromptDemo().startDemo(args);
}
private void startDemo(String[] args) {
// Outer loop to keep inner prompt loop cycling until "q" is entered:
String num = "";
while (!num.equalsIgnoreCase("q")) {
while (num.isEmpty()) {
// Prompt:
System.out.println("Please enter any legal int, long, float, or double type number:");
System.out.print("Your number (q to quit): -> ");
num = userInput.nextLine().trim();
// Is `q` for quit provided?
if (num.equalsIgnoreCase("q")) {
//Yes...
System.out.println("quiting - Bye Bye" + ls);
break; // Exit inner `while` loop and effectively, the outer loop as well:
}
/* Validate User input. Is it a string representation of
a signed or unsigned Integer or Floating-Point value: */
if (!num.matches("-?\\d+(\\.\\d+)?")) {
// No... inform User and allow to try again:
System.out.println("Invalid number supplied (" + num + ")! Try again..." + ls);
num = ""; // Empty `num` to ensure re-loop:
}
}
if (num.equalsIgnoreCase("q")) {
break;
}
// Validation Passed:
Double doubleValue = null;
Integer intValue = null;
Long longValue = null;
if (num.contains(".")) {
doubleValue = Double.valueOf(num);
}
else {
longValue = Long.valueOf(num);
if (longValue <= Integer.MAX_VALUE) {
intValue = Integer.valueOf(num);
longValue = null;
}
}
System.out.println("You entered a "
+ (doubleValue != null ? "`double` type value of: " + doubleValue
: (longValue != null ? "`long` type value of: " + longValue
: "`int` type value of: " + intValue)));
num = "";
System.out.println();
}
}
}
In the example above, the User can enter any number as long as it's a legal signed or unsigned int
, long
, float
, or double
type number. You could take this a little further and add BigInteger
and BigDecimal
to the mix.
The Regular Expression ("-?\\d+(\\.\\d+)?"
) supplied to the String#matches() method checks to see if the User supplied numerical value is in fact a signed or unsigned integer or floating-point value.
Checks for data type are done after the inner while
loop and nested Ternary Operators are used to display the result within the Console Window.