I am creating a program that is a simple mock-up of a banking account system. I have a simple method that when called asks the user to input a name (String) and a starting account balance (double) and creates a new Person object / Account object.
This method is called via a menu that uses 1-9 (int) options, and say '1' is pressed to create a new account. So the code (before accepting the string) has a default input.nextLine(); command to catch the int input before capturing the actual name input (customerName = input.nextLine();).
The issue I am having is that I am trying to add exception handling to this method to ensure that the name String input is only letters and spaces. When running the first time and someone puts an incorrect input, it would re-output the "Please input a name" but then they would have to enter the name twice since the input.nextLine(); was still in there (but not catching a menu input). So I added a if/else decision structure with a counter for the first time that the program runs if the (counter == 0) then it keeps the input.nextLine() and increments the counter, but if the (counter > 0) it gets rid of the input.nextLine() so that the program runs fine.
This causes another problem, that if the user tries to create multiple accounts, it will cause the program to stop printing the input.nextLine() the second time it is called and automatically assume the menu option input is what the name is supposed to be, and sends an error. Is there a better way to get this working the way I intended?
Sorry if the description isn't very clear, it's a hard problem to describe.
Here's the code:
public void menuOptionOne() {
do {
try {
if (counter == 0) { // counter is initially set to 0
System.out.println("Please input the customer's name: ");
input.nextLine(); // catches the menu input
customerName = input.nextLine();
matcher = pattern.matcher(customerName);
counter++; // increments the counter in case the user's input is invalid
if (!matcher.find()) { // if it has non-letter/space characters present, throws exception
throw new Exception("Try again. (Incorrect input: name must contain only letters)");
}
} else if (counter > 0) { // asks the user to input name again, without the input.nextLine() which is intended to catch the menu int input
System.out.println("Please input the customer's name: ");
customerName = input.nextLine();
matcher = pattern.matcher(customerName); // checks the input to ensure it is only letters and/or spaces
if (!matcher.find()) {
throw new Exception("Try again. (Incorrect input: name must contain only letters)");
}
}
continueInput = false;
} catch (Exception ex) {
System.out.println(ex.toString());
}
} while (continueInput);
So when this gets called twice in a row, it automatically goes to the second decision structure, without the input.nextLine(), and that catches the menu input (1) and throws the exception. How can I get it to work properly each time the method is called?
This is the output when it is called twice in a row (note: it saves the menu input as the new customer name, even though it is a number):
Please input the customer's name:
java.lang.Exception: Try again. (Incorrect input: name must contain only letters)
Please enter the new balance:
You want to do two things in the input retrieval:
allow a series of inputs by reusing this method.
check the content of the input and start again if not suitable.
The way you are using to "allow a series of inputs by reusing this method" is the source of your error.
In a general way you should favor the use of the most restricted scope when it is enough.
By declaring continueInput and counter as a field variable instead of a local variable you create a coupling between invocations of menuOptionOne().
Which explain your problem :
This causes another problem, that if the user tries to create multiple
accounts, it will cause the program to stop printing the
input.nextLine() the second time it is called and automatically assume
the menu option input is what the name is supposed to be, and sends an
error. Is there a better way to get this working the way I intended?
This code should be enough :
public void menuOptionOne() {
// change
int counter = 0;
boolean continueInput = true;
// end change
do {
try {
if (counter == 0) { // counter is initially set to 0
System.out.println("Please input the customer's name: ");
input.nextLine(); // catches the menu input
customerName = input.nextLine();
matcher = pattern.matcher(customerName);
counter++; // increments the counter in case the user's
// input is invalid
if (!matcher.find()) { // if it has non-letter/space
// characters present, throws
// exception
throw new Exception("Try again. (Incorrect input: name must contain only letters)");
}
} else if (counter > 0) { // asks the user to input name again,
// without the input.nextLine()
// which is intended to catch the
// menu int input
System.out.println("Please input the customer's name: ");
customerName = input.nextLine();
matcher = pattern.matcher(customerName); // checks the input
// to ensure it
// is only
// letters
// and/or spaces
if (!matcher.find()) {
throw new Exception("Try again. (Incorrect input: name must contain only letters)");
}
}
continueInput = false;
} catch (Exception ex) {
System.out.println(ex.toString());
}
} while (continueInput);
}
The way you are using to "check the content of the input and start again if not suitable", works but you could do much more simple and avoid repeat yourself.
Ah, I figured out my issue.
I set the variable counter = 0; at the top of my method and then at the bottom set continueInput = true; again
Now it works as intended.
So working code looks like:
public void menuOptionOne() {
counter = 0; // set counter to 0
do {
try {
if (counter == 0) {
System.out.println("Please input the customer's name: ");
input.nextLine();
customerName = input.nextLine();
matcher = pattern.matcher(customerName);
if (!matcher.find()) {
counter++;
throw new Exception("Try again. (Incorrect input: name must contain only letters)");
}
} else if (counter > 0) {
System.out.println("Please input the customer's name: ");
customerName = input.nextLine();
matcher = pattern.matcher(customerName);
if (!matcher.find()) {
throw new Exception("Try again. (Incorrect input: name must contain only letters)");
}
}
continueInput = false;
} catch (Exception ex) {
System.out.println(ex.toString());
}
} while (continueInput);
continueInput = true; // reset the continue input value
Related
I've been trying to make a while loop where I enter in a movie number until the user types 'q' for quit, but every time I enter a valid number, I have to enter it twice before it prompts me with the "Enter movie number" message again. And the break function doesn't work when I wish to leave the loop. I simply wish to enter in the movie number once and break out when I want to.
public class Main {
public static void main(String[] args) {
while(true)
{
System.out.println("Enter in movie number: ");
Scanner input = new Scanner(System.in);
if(!input.hasNextInt())
{
System.out.println("invalid input");
continue;
}
if (Integer.parseInt(input.next()) < 0)
{
System.out.println("invalid no negative numbers");
continue;
}
if(Objects.equals(input.next(), "q"))
break;
}
}
I tried other variations of the while loop, but a similar thing has happened.
I assume your intention is to get one line of input, and if it is a number, process it somehow, and if not check if the user wants to quit.
You've got a couple problems with your program, firstly, you're creating a new Scanner within the while loop, which creates unnecessary overhead. Second, you're trying to get 2 lines of input within your loop, you wait for the user to input an integer, then you try to parse that integer with input.next(). Afterwards, you call input.next() again to check if the user wants to quit. By calling next() twice, you're requiring the user to input 2 lines, causing the issue you were describing.
You can fix this by calling next() once and storing its return value in a variable, then check if it equals q for quit, otherwise you can parse an integer value from it.
Here is working code that applies fixes to these issues:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(true) {
System.out.println("Enter in a movie number:");
// Get user input
String input = scanner.next();
// If the input equals q, we break out of the loop
if(input.equalsIgnoreCase("q")) break;
int intInput;
try {
// Get integer input
intInput = Integer.parseInt(input);
} catch(NumberFormatException e) { // Input was not a number
System.out.println("Invalid, must input a number");
continue;
}
if(intInput < 0) {
System.out.println("Invalid, no negative numbers");
continue;
}
}
}
}
Also, a small note, instead of using Object.equals to check if two strings are equal you can just use the equals method inside of the String class like so: str1.equals(str2).
I was asked to run a loop that asks for user input, applies the change using the adjustPrice() method, print the new information after adjusting the price. and then finishes the loop when the user enters 0.
Right now it does all of the above, just doesn't ask for the user input again and ends with the printed new information. please help!
boolean done = false;
while (!done) {
System.out.print("Enter adjustment to price in percent (0 to quit): ");
double adjustment = in.nextDouble();
if (adjustment == 0) {
done = true;
}else{
swag.adjustPrice(adjustment);
System.out.println(swag.toString());
in.next();
}
}
You have in.next() at the end. This expects the user to input something before the loop will reset to the System.out line. Take out that line.
to allow user input using the end
else {
swag.adjustPrice(adjustment);
System.out.println(swag.toString());
in.next();
}
but beware that this method does not take keys as enter or space to
take into account these keys use.
else {
swag.adjustPrice(adjustment);
System.out.println(swag.toString());
System.in.read();
}
So I am working on a program to allow a user to add students to the class as well as manage their grades and what not. When a user selects the first option in the menu, he has to input an id (mandatory) but he could add a numerical score and/or a letter grade as well. Based on feedback in another post I managed to create a String variable line that reads user input, then checks whether it is "S"/"s" (to skip or not) and parses the value into double accordingly. Now building on the question, how can I skip the prompt and proceed to the next prompt if the user decides to skip adding a score? I have tried to use break; but it exits the entire loop . Is there a way to skip the question for score and proceed to the question for letter grade?
Output:
1) Add Students to Class
2) Remove a Student from Class
3) Set Grades for a Student
4) Edit Grades for a Student
5) Show Class Report
6) Exit
1
Kindly input id:
Kindly input Score: (Enter s to Skip)
Kindly input Grade: (Enter s to Skip)
Code
// Prompting the user for Score (Numerical Grade)
System.out.println("Kindly input Score: (Enter s to Skip)");
// reading the input into the line variable of string datatype
String line = input.nextLine();
// checking if line =="s" or =="S" to skip, otherwise
// the value is parsed into a double
if("s".equals(line) || "S".equals(line))
{
break; // this exists the loop. How can I just skip this requirement
//and go to the next prompt?
}else try
{
score = Double.parseDouble(line);
System.out.println(score);
} catch( NumberFormatException nfe)
{
}
// Prompting the user for Numerical Grade
System.out.println("Kindly input Grade: (Enter s to Skip)");
String line2 = input.nextLine();
if("s".equals(line2) || "S".equals(line2))
{
break; // this exists the loop. How can I just skip this
// requirement and go to the next prompt?
}else try
{
score = Double.parseDouble(line2);
System.out.println(score);
} catch( NumberFormatException nfe)
{
}
Just remove the break:
if("s".equals(line) || "S".equals(line))
{
// Don't need anything here.
}else {
try
{
score = Double.parseDouble(line);
System.out.println(score);
} catch( NumberFormatException nfe)
{
}
}
But it is better not to have an empty true case (or, rather, it is unnecessary):
if (!"s".equals(line) && !"S".equals(line)) {
try {
// ...
} catch (NumberFormatException nfe) {}
}
You can also use String.equalsIgnoreCase to avoid needing to test "s" and "S".
Use the continue keyword. break will exit the entire loop while continue just skips the next thing.
So this is my code i dont know what to add if i want to display invalid message for the non numeric inputs please help ty
import java.util.Scanner;
public class Date
{
public static void main (String args [])
{
int x;
Scanner in = new Scanner (System.in);
System.out.print("Enter a date ");
x = in.nextInt();
while (x < 1520 || x > 3999)
{
System.out.println ("Invalid Gregorian Calendar date.");
System.out.print ("Please Input a valid Gregorian Calendar date: ");
x = in.nextInt();
}
System.out.println("Good");
Use a try catch block, and put x = in.nextInt(); inside it
I've changed your code a bit. I think this is what you were aiming for.
I'm not that good in explaining but I try to tell what I did.
First of all I got rid of your in.nextInt() since this is very restrictive. It does only accept an integer and will throw an exception if you type something else in. Normally this would be OK, but since you want the user to be able to correct the input, this will cause more troubles than it would solve.
I then put your code into an infinite loop while(true) which assures, you do not have to restart your application again once you've typed in a wrong value.
What is going on within the loop is quite simple. The console prints out what you want the user to do and reads the consoles input as a String, so you don't have to face any exceptions in the first place.
I then try to parse the given String into an integer value. I added trim() to kill leading spaces as well as trailing, so I won't have to deal with users being confused by typing in numbers with a space since they don't directly see whats wrong when getting their "not an integer" error. This would be thrown, if the input contains spaces.
Now I check whether or not the given integer-value fits your specifiation. I don't need a loop here, so I changed it to be a simple if-statement.
If the value is wrong (or lets say the if (x < 1520 || x > 3999) returns true) I'm going to print out your error message. Since we already passed casting the String input into the integer and we do not reach the else-branch we now return back to the beginning of our loop with printing out the request again before waiting for a new input to be made.
Now, as soon as the user typed in another value, e.g. 2011 (which is valid based on your specification) we will now reach the else-branch which prints the "Good" and leaves the loop by calling break. And since there is nothing left to do for the application it will stop running. If you want the user to be able to type in new values in the positive case, you simply have to remove the break-statement.
If the user types in a value which is not an integer, the cast will fail and throw a NumberFormatException. We catch this exception by surrounding the cast with the try-catch-block and print out the integer-error once we've reached the catch-block.
Then the application reacts the same way like if you typed in a wrong number and we will return to the beginning of the loop again.
The reason for putting a try-block around the Scanner is to handle closing.
import java.util.Scanner;
public class Date {
public static void main(String args[]) {
String input = "";
int x = 0;
try (Scanner in = new Scanner(System.in);) {
while (true) {
System.out.print("Please Input a valid Gregorian Calendar date: ");
input = in.nextLine();
try {
x = Integer.parseInt(input.trim());
if (x < 1520 || x > 3999) {
System.out.println("Invalid Gregorian Calendar date.");
}
else {
System.out.println("Good");
break;
}
} catch (NumberFormatException e) {
System.out.println("Given value \"" + input.trim() + "\" is not an integer.");
}
}
}
}
}
The Scanner class has a method for this
Scanner in = new Scanner(System.in);
int x;
if(in.hasNextInt()){
x = in.nextInt();
System.out.println("Valid number");
}else{
System.out.println("Not a number");
}
To keep prompting until a valid number is entered
int x;
System.out.println("Enter a number: ");
while(!in.hasNextInt()){
System.out.println("Invalid number, try again: ");
key.nextLine(); // Flush out invalid number
}
x = key.nextInt();
I am calling this method and it works perfectly for the most part. Not sure if this is enough code for you guys to extrapolate from and figure out my problem, but I guess I will give it a shot..
When I enter an integer that is out of the bounds of the array or the file name does not exist, it throws the catch statement. I want it to then loop back to the question that the program is asking and not just continue to the rest of the program.. I keep getting an error when I throw the catch statement in the same while loop as the try statement. Thanks for the help, and I hope that was clear enough for you guys to understand.
public static String [][] placeCustomer(String [][] MovieSeats, int rows, int columns, String database)
{
//Get user data and then write the name to the array space specified by the user..
Scanner input = new Scanner(System.in);
try
{
File readFile = new File(database);
Scanner reader = new Scanner(readFile);
while (reader.hasNextLine())
{
String user = reader.nextLine();
System.out.println(user + " wants to sit in the theater. Where would you like to place him?");
String lastUser = user;
System.out.print("Row: ");
int placeRow = input.nextInt();
System.out.print("Column: ");
int placeCol = input.nextInt();
while (!MovieSeats[placeRow][placeCol].equals("Seat Empty |")) //If element in 2-D array reads empty, then tell user.
{
System.out.println("Sorry that seat is already taken.. try a different location.."); //Give them another chance to change location
System.out.println("Please enter a new location for " + user);
System.out.print("Row: ");
placeRow = input.nextInt();
System.out.print("Column: ");
placeCol = input.nextInt();
if (MovieSeats[placeRow][placeCol].equals("Seat Empty |")) //If it is empty, allow user to fill the 2-D element..
{
break;
}
}
if (MovieSeats[placeRow][placeCol].equals("Seat Empty |"))
{
while (MovieSeats[placeRow][placeCol].equals("Seat Empty |"))
{
System.out.println("The customer " + user + " has been placed at row " + placeRow + " and the column " + placeCol + ".");
System.out.println();
MovieSeats[placeRow][placeCol] = user;
System.out.println("The current seating \n________________________");
viewFilledTheater(MovieSeats, rows, columns);
System.out.println();
}
}
else
{
System.out.println("Please enter a valid value for the program to understand where you would like to place the customer...");
}
}
}
//If the file does not exist, then catch the exception, print this statement and exit the program..
catch (FileNotFoundException e)
{
System.out.println("The movie theater will remain empty because \nwe cannot find the customer list with the name you provided..");
}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println("I am sorry, but the integer you entered is not within the proper bounds of the theater..");
}
return MovieSeats;
while, I have a detailed look at your code, I think you can just make it more simple. You want ArrayIndexOutOfBoundsException to be catched and then terminal re-ask the client to input the placeRow, placeCol, so, you should put the ArrayIndexOutOfBoundsException catch clause inside the while loop, while put the FileNotFoundException catch clause outside the while loop.
Below is a simple demo on how to put the ArrayIndexOutOfBoundsException try-catch clause to meet you need
while(true){
System.out.println(user
+ " wants to sit in the theater. Where would you like to place him?");
String lastUser = user;
System.out.print("Row: ");
int placeRow = input.nextInt();
System.out.print("Column: ");
int placeCol = input.nextInt();
try{
if(!MovieSeats[placeRow][placeCol].equals("Seat Empty |")){
System.out.println("Sorry that seat is already taken.. try a different location..");
System.out.println("Please enter a new location for "+ user);
continue;
}else{
//set this seat occupied
break;
}
}catch(ArrayIndexOutOfBoundsException e){
//e.printStackTrace();
continue;
}
}
So, first off, you throw Exceptions, which are caught by catch statements (that's why they call them catch statements). Your problem is really just one of scoping. Nest your try/catch inside the relevant loop. Note that after an exception, the program resumes after the catch block(s). If needed, you can have multiple nested try/catch statements.
You should build a recursive method that does this:
step 1. check if the seats are available. If the seats are available, then place the user and display.
step 2. if the seats are not available, ask the user to see if the user likes to re-enter their choice. If YES, go to step 1. If NO, exit.
that way no matter how many times the user chooses the wrong values, he will always be given a choice to re-enter. Your program will never exit until the user chooses to.
I hope this gives you some idea. Good Luck.