I have a homework assignment to create a class with a looping menu to manage a queue of cars. We learned queues in our last class.
My menu works perfectly fine until it catches InputMismatchException or QueueEmptyException, after which it goes into endless loop, not even stopping at the userInput.nextInt();. It works when it catches QueueFullException, but not the others.
My code is:
import java.util.*;
public class CarQueueManagement {
public static void main(String[] args) throws InputMismatchException, QueueFullException{
ArrayQueue queue = new ArrayQueue(3);;
Scanner userInput = new Scanner(System.in);
int carNum;
int choice = 0;
queue.add(1);
OUTER:
while (true) {
try{
System.out.println("ΜΕΝΟΥ:\n\t1. Άφιξη αυτοκινήτου");
System.out.println("\t2. Αναχώρηση αυτοκινήτου\n\t3. Κατάσταση ουράς\n\t4. Έξοδος");
System.out.print("\n\tΕπιλογή (1-4): ");
choice = userInput.nextInt();
switch (choice){
case 1:
System.out.print("\n\tΆφιξη αυτοκινήτου:\n\t\tΑριθμός Αμαξιού");
carNum = userInput.nextInt();
queue.add(carNum);
break;
case 2:
if(queue.isEmpty()){
System.out.println("\n\tΗ ουρά είναι άδεια, δεν χριάζεται διαγραφή.\n\n");
break;
}
String answer;
while(true){
System.out.print("\n\tΑναχώρηση αυτοκινήτου\n\t\tΕπιβεβαίωση; (y/n): ");
answer = userInput.next();
if(answer.equals("y")){
queue.remove();
break;
}
else if(answer.equals("n"))
break;
}
break;
case 3:
System.out.println("\n\tΚατάσταση ουράς:");
if(queue.isEmpty()) System.out.println("\t\tΗ ουρά είναι άδεια.\n\n");
else if(queue.isFull()) System.out.println("\t\tΗ ουρά είναι γεμάτη.\n\n");
else System.out.println("\t\tΗ ουρά έχει άδιες θέσοις.\n\n");
break;
case 4:
System.out.print("\n\nΕξοδος");
break OUTER;
default:
break;
}
}catch (InputMismatchException exc){
System.out.println("\t\tΛΑΘΟΣ ΕΙΣΑΓΩΓΗ\n");
}catch(QueueEmptyException exc){
System.out.println("\t\t" + exc.getMessage() + "\n");
}catch(QueueFullException exc){
System.out.println("\t\t" + exc.getMessage() + "\n");
}
}
}
}
From the intro section of java.util.Scanner docs (emphasis mine):
When a scanner throws an InputMismatchException, the scanner will not pass the token that caused the exception, so that it may be retrieved or skipped via some other method.
Without the details, your while(true) loop is:
while (true) {
try{
choice = userInput.nextInt();
switch (choice){
case 1:
...
}
} catch (InputMismatchException exc){
// Do nothing.
}
}
When the user enters something that can't be converted to an integer, the Scanner throws an InputMismatchException, which you catch and ignore. Then the while loop goes back to the top, where it tries to execute userInput.nextInt()... but the Scanner is still looking at the same invalid input, so it immediately throws another InputMismatchException, which you catch and ignore again. Execution continues at the top of the while loop, where it calls nextInt() again... and the cycle continues forever.
You have to force the Scanner to skip the bad input, so your catch block should look something like this:
}catch (InputMismatchException exc){
System.out.println("\t\t[chastise the user in Greek]\n");
userInput.next(); // Skip invalid input.
}
Other Advice
As a general rule, lots of small methods are easier to understand than one large method. The nested while loops and switch statement were especially hard to follow. I was only able to find the bug by breaking that gigantic main method into many smaller, private static methods.
At the very least, each menu item could be handled in its own method. I also got rid of the break label by putting the whole menu into a separate method, which returned a boolean indicating whether the user was done or not. That reduced the whole loop inside main to:
boolean done = false;
while (! done) {
try{
done = handleUserInput(queue, userInput);
} catch (InputMismatchException exc) {
System.out.println("\nINPUT ERROR\n");
userInput.next();
} // Other catch blocks as before...
}
My handleUserInput doesn't do much --- it gets user input, determines which method should handle that input, and then returns true or false... It could be made simpler than this, too.
private static boolean handleUserInput(
final ArrayQueue queue,
final Scanner userInput
) {
boolean done = false;
printMenu();
int choice = userInput.nextInt();
switch (choice) {
case 1:
addToQueue(queue, userInput);
break;
case 2:
removeFromQueue(queue, userInput);
break;
case 3:
displayQueue(queue);
break;
case 4:
printExitMessage();
done = true;
break;
default:
break;
}
return done;
}
Splitting the various menu activities into separate methods made them much easier to follow. For example, when the logic was all mixed together in main, it was hard to tell if variables like carNum or answer were part of the problem. In this version, carNum is a local variable trapped inside the addToQueue method, so when I'm working anywhere else, I can completely ignore it.
Related
I am very new to Java and im trying to use try-catch statements. I would like to add a try catch case, but when i add it, the message just prints once and ends. I woudl like to reprint:
System.out.println("Press \"1\" to chat" + " & " + "\"2\" to play games" + " & \"3\" to edit the conversations");
System.out.println("Typing other numbers will end the Chatbot");
but the program just ends. Is there a way to loop the try-catch statement?
Scanner userinput = new Scanner(System.in);
int startup;
//popup for 1 to chat, 2 to play and 3 to edit
while (true) {
try {
System.out.println("Press \"1\" to chat" + " & " + "\"2\" to play games" + " & \"3\" to edit the conversations");
System.out.println("Typing other numbers will end the Chatbot");
startup = userinput.nextInt();
switch (startup) {
case 1:
ConversationBot chat = new ConversationBot();
chat.ChattingBot();
break;
case 2:
GameBot game = new GameBot();
game.GamingBot();
break;
case 3:
EditBot edit = new EditBot();
edit.EditingBot();
break;
default:
System.exit(0);
}
} catch (InputMismatchException e) {
System.out.println("Invalid User Input. Please enter a value from 0 to 4.");
break;
}
String returningCode = returnChoiceOfChatbot(startup);
System.out.println(returningCode);
}
Thank you for the help.
BTW this is the returnChoiceOf Chatbot method
public static String returnChoiceOfChatbot(int input) {
String returnChoice = null;
switch (input) {
case 1:
returnChoice = ("You have chosen to chat with me!");
break;
case 2:
returnChoice = ("you have chsen to play word games with me!");
break;
case 3:
returnChoice = ("Please enter an input that you would give to the Chatbot.");
break;
default:
System.exit(0);
}
return returnChoice;
}//end of returnChoice method
You need to replace the line break; with continue; in your catch block. You want to ask the user for a new input if it wasn't a number. Otherwise that break breaks the whole while loop and prevents it from running again. This said, it should read:
} catch (InputMismatchException e) {
System.out.println("Invalid User Input. Please enter a value from 0 to 4.");
continue; // Jump back to the beginning of the while-loop
}
Also check if you need to move these two lines:
String returningCode = returnChoiceOfChatbot(startup);
System.out.println(returningCode);
outside of your while loop. While it's not clear to me what they are for, it looks like you might want to run them only once after the while loop was left.
The break statement (when used without a label to specify what to break out of) will exit the nearest switch, while, for or do .. while loop.
You generally have to use it with switch as you do to stop the execution falling through to the next case - e.g. if you didn't have the breaks and the user selected 1, it would execute the code for all three cases, and then exit the program.
Inside your catch block however, the break exits the while loop. Since the intention is to tell the user their input is invalid and then ask for new input, this isn't what you want to do here. You could change the break to a continue which would abort the current iteration of the while loop and start the loop again, however generally speaking this sort of flow control will make your program harder to follow and therefore maintain.
I'm guessing you put the last break in to skip over the returnChoiceOfChatbot(...) code when the input is invalid. But this is exactly what exceptions are for - aborting the normal flow of code when something unexpected happens. So just move the "normal flow" code all inside the try block, and you won't need break (or continue) at all:
while (true) {
try {
System.out.println("Press \"1\" to chat" + " & " + "\"2\" to play games" + " & \"3\" to edit the conversations");
System.out.println("Typing other numbers will end the Chatbot");
startup = userinput.nextInt();
switch (startup) {
// cases in here as before, omitted for brevity
}
String returningCode = returnChoiceOfChatbot(startup);
System.out.println(returningCode);
} catch (InputMismatchException e) {
System.out.println("Invalid User Input. Please enter a value from 0 to 4.");
}
}
} catch (InputMismatchException e) {
System.out.println("Invalid User Input. Please enter a value from 0 to 4.");
break;
}
Just remove the break. It doesn't have anything to do with the catch specifically, just with the break that you wrote in it.
I'm a beginner at Java and I want to get into it and I enjoy playing around with it. So I started doing an online course.
So after a few videos I learned a bit about switch statements and wanted to know how to loop them effectively.
package v1;
import java.util.Scanner;
public class Computer {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Computer is booting up...");
System.out.println("Welcome to Mindows '93, please enter a command.");
String command = input.nextLine();
boolean computerON = true;
while (computerON) {
switch (command) {
case "!music":
System.out.println("Playing music!");
break;
case "!browse":
System.out.println("Launching browser...");
break;
case "!help":
System.out.println("Here are the commands that can be used !music, !browse, !shutdown");
break;
case "!shutdown":
System.out.println("Shutting down Mindows, goodbye!");
break;
default:
System.out.println("Command not recognised, type !help for a list of commands...");
break;
}
if (command.equals("!shutdown")) {
computerON = false;
}
}
}
}
So basically what I want is to make a mock text-based OS called Mindows with very limited functionality, but I'm having problems.
When I input !music, the program will constantly spam lines of "Playing music!"
When I enter !shutdown, however, it terminates which is what I want.
What I want is to type !music, !browse, !help and (x) to get the default message without the program spamming lines OR terminating.
I want to be able to type these commands in constantly until the !shutdown command is issued.
You read the command only once, out of your loop.
Try moving the line:
String command = input.nextLine();
into the while loop.
You're going into an infinite loop because you are accepting input from the user before the loop, and the input doesn't change during the execution of the loop. So if you entered "!music", the command doesn't change throughout the loop and the switch statement always goes into case "!music": in each iteration of the loop, which is why computerON is always true and the loop executes and prints "Playing music" infinitely.
The solution to this would be to move the String command = input.nextLine(); statement inside the while loop, like the above answers say.
Changed your logic here :
boolean computerON = true;
while (computerON) {
String command = input.nextLine();
switch (command) {
case "!music":
System.out.println("Playing music!"); break;
case "!browse":
System.out.println("Launching browser...");
break;
case "!help":
System.out.println("Here are the commands that can be used !music, !browse, !shutdown");
break;
case "!shutdown":
System.out.println("Shutting down Mindows, goodbye!");
break;
default:
System.out.println("Command not recognised, type !help for a list of commands...");
break;
}
if (command.equals("!shutdown")){
computerON = false;
}
}
I have some code that involves checking user input to see if it the input entered is a string or an int, and will execute different code depending on the result. I am using Integer.parseInt in order to determine if the user input is an integer or not, with the NumberFormatException being thrown if it is not.
However, in order to control the flow of the code, i am using a try/catch statement, with the catch block being used to contain code that will be run if the user's input is a string (i.e NumberFormatException) is thrown.
Qn
Is this an acceptable way of using the try/catch block? I've try googling this but all i could find were examples of the catch block being used to handle the Exception thrown instead of it being used as i am doing.
import java.io.*;
import java.util.*;
public class Datafile{
private static Scanner input = new Scanner(System.in);
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\Kence\\workspace\\Java 8 - Beyond the Basics - Working Files\\Practice Programs\\src\\Practice Data Edited",true));
String data = null;
boolean end = false;
boolean cont = true;
String dataEntered = null;
int menuChoice = printMenu();
while(!end){
switch(menuChoice){
case 1:
System.out.println("Please enter a line of data or press 0 to exit back to the main menu");
dataEntered = input.nextLine();
try {
if(Integer.parseInt(dataEntered) == 0){
break;
}
} catch (Exception e) {
data += dataEntered + "\n";
while(cont){
System.out.println("Data entered.Please enter the next line of data or press quit to exit back to the main menu.");
dataEntered = input.nextLine();
if(Integer.parseInt(dataEntered) == 0){
cont = false;
break;
}else{
data+= dataEntered;
System.out.println("Current data entered is " + dataEntered);
}
}
}
break;
case 2:
System.out.println("2 Entered");
break;
case 3:
System.out.println("3 Entered");
break;
case 4:
System.out.println("4 Entered");
break;
}//End of switch statement
menuChoice = printMenu();
}
input.close();
}//End of main
public static void printStars(){
for(int i = 0; i<66 ; i++){
System.out.print("*");
}
System.out.println();
}
public static int printMenu(){
printStars();
System.out.println("System Started");
printStars();
System.out.println("Enter 1 to input a new line of data");
System.out.println("Enter 2 to list all data");
System.out.println("Enter 3 to save existing data");
System.out.println("Enter 4 to load data");
printStars();
return Integer.parseInt(input.nextLine());
}
}
It isn't considered best practices to use a try/catch block for control flow, but it is "acceptable" if you don't care about best practices.
See Determine if a String is an Integer in Java for examples of other ways to check if a number is an integer. You could use one of those examples and then if it is an integer check if it's equal to zero.
Also, in your code it appears your second call to Integer.parseInt(dataEntered) could still throw an exception that would not be caught.
Exceptions should generally only be used in exceptional cases (see where the name comes from?). They are especially bad in tight loops because the execution overhead is high. Having invalid user input seems like a rather common occurrence, so I would look for another way. Take a look at this answer.
But this all depends on the language. In Python for example, try/catch is the de-facto way of coding (duck-typing).
In my code below im am tring to add a thread.sleep for when someone chooses the option to exit the lift, i am not sure whats wrong with the code i entered to make it sleep.I already included the Interrupted exception so can someone tell me where i went wrong.
import java.util.Arrays;
import java.util.Scanner;
public class username{
public static void main(String... args) throws InterruptedException {
String[] verifiedNames = { "barry", "matty", "olly", "joey" };
System.out.println("choose an option");
System.out.println("Uselift(1)");
System.out.println("see audit report(2)");
System.out.println("Exit Lift(3)");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
switch (choice) {
case 1:
scanner.nextLine(); // get '\n' symbol from previous input
int nameAttemptsLeft = 3;
while (nameAttemptsLeft-- > 0) {
System.out.println(" Enter your name ");
String name = scanner.nextLine();
if (Arrays.asList(verifiedNames).contains(name)) {
System.out.println("dear " + name + " you are verified " +
"you may use the lift, calling lift ");
break; // break out of loop
}
}
if (nameAttemptsLeft < 0) {
System.out.println("Username Invalid");
}
break;
case 2:
System.out.println("option 2");
break;
case 3:
System.out.println(" Please Exit Lift ");
Thread.sleep(5000);
System.exit(0);
break;
}
You're ending your program after the sleep returns.
Thread.sleep(5000);
System.exit(0);
Maybe you're looking for a loop of some kind. You haven't shown us what comes after the switch, but maybe that System.exit(0), which stops the java process, shouldn't be there.
Get rid of the System.exit(0)
Wrap your method in a loop if you want it to loop. My example is an infinite loop, but if your application accepts user input you can just as easily have a boolean flag that serves as the loop condition.
public static void main(String... args) throws InterruptedException {
while(true){
//all of your code
}
}
Also you should surround your sleep in a try-catch instead of declaring a throws on your main method... it is good practice to catch exceptions you can handle, and throw exceptions that you cannot handle to earlier stack frames that can. Typically you don't want your main() method to have a throws clause as it can cause the premature termination of your application. This doesn't really matter for InterruptedException in your specific case, but does for many other exceptions.
Can someone please highlight to me the problem With my main method? I am getting the error exception that scanner is closed once I complete first option and try to enter another?
I think the problem I am having is from the placement of my try catch and finally blocks but not totally sure! Thanks!
/**
* Scanner used for input within program
*/
public static Scanner scanner = new Scanner(System.in);
/**
* Main method that provides user with a menu in which each number
* represents a different task in which they can carry out
*/
public static void main(String[] args) {
int menuOption=0;
do{
try {
// Declaring var for user Input (defaulted to 0)
menuOption = showMenu();
switch (menuOption) {
case 1:
add();
break;
case 2:
subtract();
break;
case 3:
generateRandomNumber();
guessRandomNumber();
break;
case 4: // invoke print loop method (use params here to get
// experience!)
break;
case 5: // invoke print sum and average
break;
case 6: System.out.println("Quitting Program...");
break;
default:
System.out.println("Sorry, please enter valid Option");
}// End of switch statement
} catch (Exception ex) {
//flush scanner
scanner.next();
}
finally {
// Finally block ensures scanner is always closed
scanner.close();
}
}while(menuOption!=6);
//Exiting message
System.out.println("Thanks for using this Program...");
The problem is that in the first iteration of the loop you are closing the scanner in the finally block. The finally block goes off every time, even if a exception isn't caught.
I'm guessing you're using exceptions for program flow (and catch-all at that!)? Don't. Exceptions are very expensive and using them for program flow clutters the code a lot.
You're using scanner.next() in your catch statement: this will ask for new input.
But since the finally block is executed right after the catch, you'll immediatly close it.
The finally block will execute regardless of exceptions or not. It is meant to clean up resources, but you're cleaning them too early.
Remove the try-catch (or make it more appropriate) and don't close your scanner in the finally block.
Close the scanner outside of the loop and get rid of the finally
do {
...
} while (...)
scanner.close();
Right now your flow of control looks like this
do {
try {
//read from scanner
}
finally {
scanner.close();
}
} while (menuOption != 6);
but this closes your scanner after first iteration.
You probably should move your do...while() inside try{...} block.
try {
do{
//read from scanner
}
while (menuOption != 6);
}
finally {
scanner.close();
}
This way your finally block which ensures closing of scanner will be outside of loop.
Mayby you get and exception and the code enters in the catch then in finally
Tray to see if you enter in the catch block