I've made a choice menu in a while loop. To make sure that users put in a valid choice, i put the menu itself in a try catch block:
I want the user to get a new chance if an exception was caught, so I put the try-catch block in a while(true) loop. However, using this kind of loop, the part where the actions are coded becomes unreachable code.
Is there a way to do this better?
And an extra question, How do i prevent a user from entering a choice option that does not exist?
while (choice != 0) {
/* Ask for player's choice */
while(true) {
try
{
BufferedReader menuInput = new BufferedReader(new InputStreamReader(System.in));
System.out.println();
System.out.println("Please choose between the following options:'");
System.out.println(" (1) Make new animal");
System.out.println(" (2) Feed Animals");
System.out.println(" (3) Count animals");
System.out.println(" (0) Quit");
System.out.print("Enter your choice: ");;
choice = Integer.parseInt(menuInput.readLine());
} catch (NumberFormatException ex) {
System.err.println("Not a valid number");
} catch (IOException e) {
System.out.println("Failed to get input");
}
}
// first choice option:
if (choice == 1) {
//actions
}
// second choice option:
if (choice == 2) {
//actions
}
// third choice option:
if (choice == 3) {
//actions
}
}
System.out.print("Thank you for playing!")
The very simplest way of doing it is to set a boolean flag above your loop:
boolean waitingForAnswer = true;
and then just change your while loop condition to while(waitingForAnswer) and set waitingForAnswer to false after one has been accepted.
You can then use that same structure to prevent them entering 5, or whatever. Simply tag an if on the end there that checks if the value is an accepted one, if it isn't, don't change waitingForAnswer
EDIT:
Incidentally, your string of if statements at the bottom isn't terribly efficient. If the user inputs "1" then the if (choice==1) block will trigger and it will then go on to check if it equals 2, if it equals 3, etc when we know for a fact it won't. Use else if there.
Another EDIT:
Also, create your input stream reader outside of the loop. Currently you're creating a new one each time the loop runs.
Related
first question:
There is a do while loop, within the do section there is a switch. After selection case 1, some calculations are done, two options can result as shown in the If statement. My problem is code runs until the break; then just goes straight back to the menu loop. My question: how do i get the program to print the output for the user, then continue the menu loop?
Second question:
In case 1 there are two resulting options, the first being a failed response. from here, how do i get the program to loop back to the start of case 1 to ask for user input again? Even back to the main menu would be fine.
public static void showMenu() {
System.out.print('\u000c');
System.out.println("1 - Compute Change \n");
System.out.println("2 - Estimate Feast \n");
System.out.println("3 - \n");
System.out.println("4 - \n");
System.out.println("5 - I'm broke, get me out of here\n");
System.out.println("Select Option:\n");
}
public StackPost() {
System.out.println("Welcome to the Bank of Winterfell");
Scanner in = new Scanner(System.in);
do {
showMenu();
selection = in.nextInt();
switch (selection) {
case 1:
// get input, compute then decision:
if (something<somethingElse) {
// false response -
} else {
// correct response - system prints out some stuff back to user, back to main
// menu loop
}
break;
case 2:
break;
case 5:
System.out.println("\nEnding Now\n");
System.exit(0);
break;
default:
System.out.println("Instruction is invalid");
}
} while (selection != 5);
}
You could print "Press enter to continue" (or whatever you want to give notice of before locking the program), and add a call to Scanner#nextLine() before your break. This will lock the progression 'till user presses enter.
case 2:
// Some code here...
// Done, now show result and tell user to press any key to continue
System.out.println("Some fancy result from case handle code");
System.out.println("Press enter to continue...");
in.nextLine();
break;
You could add a while-loop that won't let the code continue 'till whatever input is expected in the first case is acceptable.
case 1:
System.out.println("Some handle that tells user to input something, and what is acceptable");
String input = null;
while(!(input = in.nextLine()).equals("something")) {
System.out.println("Wrong input, try again...");
}
// Input is acceptable, now do something with it...
System.out.println(input);
System.out.println("Press enter to continue...");
in.nextLine();
break;
Be aware, in your code, you call Scanner#nextInt(), and #nextInt doesn't consume the \n from pressing enter, and will thus be transferred into the switch case's usage of #nextLine(). You could avoid this with selection = Integer.parseInt(in.nextLine()).
You can use achieve it by:
For First question: Using return statement in case of correct response.
For Second question: Using while loop in case 1
After implementaing the proposed solution the StackPost() method will look like following. You can see the complete working code here:
public static void StackPost()
{
System.out.println("Welcome to the Bank of Winterfell");
try(Scanner in = new Scanner(System.in))
{
int selection;
do
{
showMenu();
selection = in.nextInt();
switch (selection)
{
case 1:
// get input, compute then decision:
while(true)
{
int something = in.nextInt();
int somethingElse = in.nextInt();
if (!(something<somethingElse)) {
// correct response - system prints out some stuff back to user, back to main
System.out.println("Print here the result");
// menu loop
return;
}
// false response - continue for next iteration in while-loop
}
//No need of 'break;' here
case 2:
break;
case 5:
System.out.println("\nEnding Now\n");
System.exit(0);
default:
System.out.println("Instruction is invalid");
}
} while (selection != 5);
}
}
Note: It is best practice to use try-with-resources while handling system resources which implements AutoCloseable interface.
My code below is looping twice. The 1st while loop before it asks for user input (to make a choice). I made it simpler by putting choice default is "N".
So it hits the if statement and begins the 2nd while loop. Now it asks the user for another choice. The user can only enter "A" as anything else will error trap. The user enters "A" and gets prompted to add a number (the variable num = 0). User enters a number.
The if statement closes, and the 2nd while loop comes back to the top, only it doesn't stop when the user is asked for a choice. Instead, it continues through the loop, hits the else statement, then comes back to the top of the 2nd while loop again and presents the user with a prompt for a choice.
Code Updated with More Information
while (true) { // 1st while loop
choice="N";
if (choice.equalsIgnoreCase("N")) {
while (true) { // 2nd while loop
System.out.println("|-|-| Add Number [A] Go Back [B]");
System.out.println("NUMBER: "+num);
System.out.print("Choice: ");
choice = c.nextLine();
if (choice.equalsIgnoreCase("A")){
System.out.print("Add: ");
num = (c.nextInt() + num);
System.out.println("");
}
else if (choice.equalsIgnoreCase("B")){
break;
}
else {
System.out.println("ERROR 19: Invalid response");
System.out.println("");
}
}
}
}
I have tried using different variables for choice. It did not work. I think I may need to try catch just below the 2nd while loop (before the user is prompted for a number), but that's only a idea. My question would be, why is this happening? And if possible, how can I fix it?
In your code while(true) will keep looping indefinitely. Either change the condition from always true to something which is conditionally true (using an if condition inside the while loop or a for loop). Or use a mix of break, return and continue when you think looping should stop.
Add a break statement in both if and else statement :
if (choice.equalsIgnoreCase("A")){
System.out.print("Add: ");
num = (c.nextInt() + num);
System.out.println("");
break;
}
else {
System.out.println("ERROR 19: Invalid response");
System.out.println("");
break;
}
I think you should change your loop. I suggest loop with like this :
boolean finished = false;
while(!finished) {
...
choice = c.nextLine();
if (choice.equalsIgnoreCase("A")){
System.out.print("Add: ");
num = (c.nextInt() + num);
System.out.println("");
} else if (choice.equalsIgnoreCase("Exit")) { //You can change this whatever you want
finished = true;
} else if (...){
... //another choice
}
else {
System.out.println("ERROR 19: Invalid response");
System.out.println("");
}
}
The Scanner#nextLine consumes the full line (hence "next line") of the user input. That's why you never get a repeated loop while using nextLine. The Scanner#nextInt does not, and the last newline character is consumed the next time Scanner#nextInt is called.
To answer my question:
if (choice.equalsIgnoreCase("A")){
System.out.print("Add: ");
num = (c.nextInt() + num); //Prompts user for input (number)
c.nextLine(); // Consumes the last newline character
System.out.println("");
}
else if (choice.equalsIgnoreCase("B")){
break;
}
else {
System.out.println("ERROR 19: Invalid response");
System.out.println("");
int option = input.nextInt();
input.nextLine(); // Consume newline left-over
String str1 = input.nextLine();
As answered from here: Scanner is skipping nextLine() after using next(), nextInt() or other nextFoo() methods
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.
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.
The following code is in a while loop which then houses a switch as such:
System.out.println("Enter in a selection.");
System.out.println("Enter \"1\" for a default selection of die");
System.out.println("Enter \"2\" for a custom number of sides.");
//try the input to see if its an integer
try {
selection = sc.nextInt();
} catch (NumberFormatException e){
System.out.print("Your selection can only be an integer!");
}
switch (selection){
case1:
...
break;
case2:
...
break;
default:
...
//yell at them
continue;
}
I already have a default selection in the switch so that if a user enters in an invalid number like 4 (since there are only 2 cases) that it brings them back to the beginning of the loop. So, the issue is handling the exception. The exception does not get handled with the following above code and I don't know why. The try is housing the offending code.
As always, please ask for clarification if needed. Thanks.
The reason exception is not handled when you enter 4 is that 4 is a valid integer and nextInt() will not raise NumberFormatException exception.
You'd better enclose the switch in the try block.
Personally, I would put your input (and the try/catch block that goes with it) in its own, separate method. Return a boolean (true = valid integer) or a value that's out of range (perhaps "-1", depending on your program).
IMHO...
Scanner#nextInt() doesn't throw NumberFormatException
Scans the next token of the input as an int. An invocation of this method of the form nextInt() behaves in exactly the same way as the invocation nextInt(radix) , where radix< is the default radix of this scanner.
return the int scanned from the input
throws InputMismatchException
if the next token does not match the <i>Integer</i>
regular expression, or is out of range
throws NoSuchElementException if input is exhausted
throws IllegalStateException if this scanner is closed
Your exception handling seems right, with only issue that you are catching wrong exception. Please catch InputMismatchException and other two.
e.g. below:
try {
selection = sc.nextInt();
} catch (InputMismatchException e){
System.out.print("Your selection can only be an integer!");
}
Also you may want to put the above code in a while loop as below:
boolean validInput = false;
while(!validInput){
try {
selection = sc.nextInt();
validInput = true;
} catch (InputMismatchException e){
System.out.print("Your selection can only be an integer!");
}
}
This will repeatedly ask for input until a number is entered.
You should continue on the exception as there is no point in going ahead do the switch on the selection if the exception occurred.
} catch (InputMismatchException e){
System.out.print("Your selection can only be an integer!");
sc.nextLine();
continue;
}
The way you have it right now, if the exception were to occur you would be switching the old stale value held by selection.
But the main problem in your code is that the nextInt() method doesn't throw the NumberFormatException, instead it throws the InputMismatchException.
So you are trying to catch the wrong exception.
In the case of a Scanner, you can use the hasNextInt() method (and equivalents for other data types) rather than crashing and burning via exception:
while (some_condition) {
System.out.println("Enter in a selection.");
System.out.println("Enter \"1\" for a default selection of die");
System.out.println("Enter \"2\" for a custom number of sides.");
//try the input to see if its an integer
if (!sc.hasNextInt()) {
System.out.println("You must enter an integer!");
continue;
}
selection = sc.nextInt();
switch (selection){
case 1:
...
break;
case 2:
...
break;
default:
...
//yell at them
continue;
}
}
As Bhesh Gurung said, if you're in a loop, you should just use continue to go back to the beginning, like you do in the default case.
If you want to really handle the exception in the 'switch' statement, you need to expand the scope of the try-catch block:
System.out.println("Enter in a selection.");
System.out.println("Enter \"1\" for a default selection of die");
System.out.println("Enter \"2\" for a custom number of sides.");
//try the input to see if its an integer
try {
selection = sc.nextInt();
switch (selection){
case1:
...
break;
case2:
...
break;
default:
...
//yell at them
throw new NumberFormatException("Yelling message");
continue;
}
} catch (NumberFormatException e){
System.out.print("Your selection can only be an integer!");
}