Reputation: 163
There are a bunch of threads throughout the internet on this but I can't make heads or tails of any of them.
As an assignment for an intro to Java course we have been tasked with making a handful of different programs, we were then given them back and told to make them idiot proof.
So for example, we have to use a program to determine what day of the week a random day of any random year will be, (i.e Jan 1 2013 being a Tuesday)
I prompt for three things, Day, Year and Month, I want to make it so that if Day is contains a letter it sends back Invalid and prompts again.
Right now I have it set so that if day is an integer less than one or greater than 31 it asks again, so I don't have a problem with the range, just the NFE.
I have heard that I should use a
Try
{
//...
}
catch{NumberFormatExcept nFE}
but I have no idea how to use that to re-prompt for what I an looking for
Here is a snippet of my code so far
System.out.print("Enter the day of the month (1-31): ");
int d = UserInput.nextInt();
do
{
if(d < 1 || d > 31)
{
System.out.print("That day is invalid, please enter a day between 1 and 31");
d = UserInput.nextInt();
}
}while(d < 1 || d > 31);
I tried making d a string and using Integer.parseInt(); but that would just parse a into 1, I want to so something like if d.hasNextInt(); continue, but if it hasNextString() reprompt.
AKA
String d;
d = UserInput.nextLine();
int dVar = Integer.parseInt(d);
I can't just throw an exception because the objective is to not crash but just prompt again.
Upvotes: 0
Views: 6402
Reputation: 269657
It looks like you are using Scanner
to get input. (By the way, in Java, it is conventional for variables to start with lower-case letters).
If that's the case, if you attempt to scan an int
when there isn't one in the input, an InputMismatchException
will be thrown. You avoid this by testing whether this will happen before you try to read the int
.
So, think about a loop structure like this:
int d = 0;
while (true) {
if (/* The input isn't an integer */) {
/* Tell the user. */
continue;
}
d = input.nextInt();
if (/* The input is out of range */) {
/* Tell the user. */
continue;
}
...
/* When you've completed all of your tests and everything is okay, break. */
break;
}
By the way, many months don't have 31 days.
Upvotes: 1
Reputation: 76898
First off, you really shouldn't use exceptions for input validations. Exceptions are for exceptional conditions; things you don't expect to happen. Josh Bloch outlines this specifically in his excellent book Effective Java
As for your code, I would suggest using the hasNextInt()
method combined with getting the input as an int and checking for the range you require as you've actually stated in your question.
int d = 0;
while (d < 1 || d > 31)
{
System.out.print("Enter the day of the month (1-31): ");
if (userInput.hasNextInt())
{
int d = userInput.nextInt();
}
else
{
String s = userInput.next();
}
if(d < 1 || d > 31)
{
System.out.print("That day is invalid - ");
}
}
Upvotes: 1
Reputation: 71565
Are you familiar with the behavior of a try-catch statement?
try
{
//do something that may throw an exception you can handle
}
catch(Exception ex)
{
//If we enter this block, an exception was thrown from the try block's code
//If you cannot fully handle the exception, you can rethrow it
throw ex;
}
finally
{
//This code ALWAYS executes, unless the program is aborted from outside its scope
}
You can use this inside some other loop, allowing you to define behavior based on whether an exception was thrown. This code is in C#; it is syntactically very close to Java but I'm a little light on Java's libraries so substitute proper class names/method calls as necessary:
int day = 0;
while(true) //we will manually break out of the loop once the user enters a valid value
{
try
{
//Ask user for input
string input = Console.ReadLine();
day = Int32.Parse(input); //this will throw an exception if input is not numeric
//You can throw your own exception within a try block too
if (day < 1 || day > 31) throw new Exception("Date not within proper bounds");
break; //if the parse worked and the value passed the validation, end the loop.
}
catch(Exception ex) //You can catch something more specific
{
//The parse failed; tell the user that they screwed up, and how
Console.WriteLine("Invalid entry: " + ex.Message);
//skip the rest of the loop's code and start a new iteration of the loop
continue;
}
}
The behavior of this construct is that while the user keeps entering values that cannot be turned into a number between 1 and 31, exceptions will be thrown, caught, and used to perpetuate the loop. As soon as the user enters something you can work with, execution flow will move past this loop to whatever is next.
Upvotes: 0
Reputation: 32949
Consider creating a method for reading in a valid integer. Pass this method the valid integer range. The method would attempt to read the value once and validate. If the method fails, return null
, if it passes return the Integer
. Call this method in a do-while
loop until you get a non-null Integer
.
Upvotes: 2