Programming beginner here, I am having trouble with error/exception handling as I do not have a clue how to do it. For my menu system (code below), I want it to alert users when anything other than 1-6 is entered, is try catch the best method? Can someone show me how it should be implemented?
do
if (choice == 1) {
System.out.println("You have chosen to add a book\n");
addBook();
}
///load add options
else if (choice == 2) {
System.out.println("Books available are:\n");
DisplayAvailableBooks(); //call method
}
////load array of available books
else if (choice == 3) {
System.out.println("Books currently out on loan are:\n");
DisplayLoanedBooks(); //call method
}
//display array of borrowed books
else if (choice == 4) {
System.out.println("You have chosen to borrow a book\n");
borrowBook(); //call method
}
//enter details of book to borrow plus student details
else if (choice == 5) {
System.out.println("What book are you returning?\n");
returnBook(); //call method
}
//ask for title of book being returned
else if (choice == 6) {
System.out.println("You have chosen to write details to file\n");
saveToFile(); //call method
}
while (choice != 1 && choice != 2 && choice != 3 && choice != 4 && choice != 5 && choice != 6) ;
menu();
keyboard.nextLine();//catches the return character for the next time round the loop
}
Try a switch statement
switch() {
case 1:
addBook();
break;
// etc ...
default:
System.out.println("Not a valid choice");
break;
}
The switch will also work with strings so you can add a q to the menu to quit or a b to go back to make a multi level menu.
This may be whats needed as all user input from readline is considered a string so unless you are converting the input to int, which will need to be wrapped in a try catch, this is the better option as the default will take care of any unexpected user input.
case "1": & case "q":
A more "clean" and much more understandable way to write it would be something like this
if(choice < 1 || choice > 6) {
//invalid input handling
}
while (choice >= 1 && choice <=6) {
// choice handling and program execution
}
Another option you can try is use a switch statement which you can study here
http://www.tutorialspoint.com/javaexamples/method_enum.htm
And the other comments are correct, this is not exception handling and rather undesirable input handling. Exception handling would be for example inputing a null and a null exception error is thrown. There you could use a try catch to continue running your program even if an error is thrown.
Related
I noticed a problem while I was programming in Java. It has been ~6 years since I've messed with Java (I've been doing front end design and development and haven't needed to program with Java since High School). I was trying to refresh my mind and do some object oriented programming and came across an issue I haven't seen before.
I was trying to setup a school database (more specifically a simple interface), and my else statement always ran even after my if statement passed. Can anyone explain to me why the else statement would run even when the if statement passes?
else {
System.out.println("Bart, come to Principal Skinner's office immediately. You broke the system. \n");
}
I wasn't able to fix this until I changed my else statement to an else if statement (to specifically disclude those if statements).
else if(!input.equals("1") && !input.equals("2") && !input.equals("3") && !input.equals("4"))
{
System.out.println("Bart, come to Principal Skinner's office immediately. You broke the system. \n");
}
Here is what the code was:
Scanner scanner = new Scanner(System.in);
int end = 0;
while(end == 0)
{
System.out.println("Welcome to Springfield Elementary School");
System.out.println("----------------------------------------");
System.out.println("Please select from the following options");
System.out.println("1) Add Course");
System.out.println("2) Remove Course");
System.out.println("3) View All Courses");
System.out.println("4) Exit");
System.out.print("-->");
String input = scanner.nextLine();
if(input.equals("1"))
{
System.out.println("That function is currently unavailable at this time");
}
if(input.equals("2"))
{
System.out.println("That function is currently unavailable at this time");
}
if(input.equals("3"))
{
System.out.println("That function is currently unavailable at this time");
}
if(input.equals("4"))
{
end = 1;
System.out.println("Thanks for accessing the Springfield Elementary School Database. Have a nice day.");
}
else {
System.out.println("Bart, come to Principal Skinner's office immediately. You broke the system. \n");
}
}
I'm not really interested in if this works or not, but why this else if works and the else statement doesn't. This isn't for school or work, but for pure learning. From my understanding of if statements, if they passed, they should skip all other conditional statements, unless it is an else if. This would seem to contradict that.
Why is my else statement always running inside my while loop?
If statements are very simple, and the problem you ran into was very simple as well. When you do
if(cond1){
code1
}
if(cond2){
code2
}else{
code3
}
It evalutes, if cond1 is true, then run cond 1. Then it does: if cond2 is true, run code2, otherwise (else) run code3.
You had all your if statements separate so the only one the else applied to was the last one. What you were looking for was an else-if.
e.g.
if(cond1){
code1
}else if(cond2){
code2
}else{
code3
}
This will only run that last else statement if all of your if statements evaluate to false.
Alternatively you can use a switch statement, these can be more confusing and sometimes more powerful, so I'll just link to it and let you read about it. https://www.w3schools.com/java/java_switch.asp
else is only applicable to the last if statement(the one checking for "4"), if you don't want to check other conditions once one is true, either use switch or add continue; inside if.
i.e.:
if(input.equals("1")) {
System.out.println("That function is currently unavailable at this time");
continue;
}
if(input.equals("2")) {
System.out.println("That function is currently unavailable at this time");
continue;
}
...
switch example:
Scanner scanner = new Scanner(System.in);
int end = 0;
while(end == 0)
{
System.out.println("Welcome to Springfield Elementary School");
System.out.println("----------------------------------------");
System.out.println("Please select from the following options");
System.out.println("1) Add Course");
System.out.println("2) Remove Course");
System.out.println("3) View All Courses");
System.out.println("4) Exit");
System.out.print("-->");
String input = scanner.nextLine();
switch(input) {
case "1":
case "2":
case "3":
System.out.println("That function is currently unavailable at this time");
break;
case "4":
end = 1;
System.out.println("Thanks for accessing the Springfield Elementary School Database. Have a nice day.");
break;
deafult:
System.out.println("Bart, come to Principal Skinner's office immediately. You broke the system. \n");
}
}
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.
I'm having a problem handling exceptions. Honestly, I really don't understand how it works since I self study.
I'm working with a program where there would be a main menu with the following choices.
Odd/Even - asks an integer input from user and identify if it is an odd or even. Program would continuously ask for an integer input if the user keeps on giving character inputs. (I was able to do this but I keep on getting errors when I use br.readLine() in getting input. Pls see codes below. So I used the normal parsing. Since I didn't use Buffered Reader, I try to delete it but the Odd/Even program wouldn't handle the exception without it.)
Vowel/Consonant - asks the user for a character input and identify if it is a vowel or a consonant. Program should reject integer inputs. The program I made with the codes below doesn't reject integer inputs. I tried searching for answers but I can't find one.
Please ignore for now.
My problem/s involve/s the following questions.
1. Why doesn't the program Odd/Even handle the NumberFormat exception whenever I try to delete the BufferedReader line even though it wasn't used in the whole program?
How can I reject integer inputs for the Vowel/Consonant program?
Here is a video when I tried to run the program.
http://tinypic.com/r/24ou9kz/9
When I exit the program, the console shows this.
Exception in thread "main" java.lang.NumberFormatException: null at
java.lang.Integer.parseInt(Unknown Source) at
java.lang.Integer.parseInt(Unknown Source)
import javax.swing.JOptionPane;
import java.io.*;
import java.util.InputMismatchException;
public class DoWhileIf {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input;
int choice, num = 0;
char again = 0;
boolean err = true;
do {
input = JOptionPane.showInputDialog("Menu\n[1] Odd/Even\n[2] Vowel/Consonant\n[3] CQM\n[4] Fuel Efficiency\n[5] Scholarship\n[6] Exit program.\n\nEnter Choice.");
choice = Integer.parseInt(input);
if (choice == 1) {
do {
do {
try {
input = JOptionPane.showInputDialog("Input an integer : ");
num = Integer.parseInt(input);
err = false;
} catch (NumberFormatException o) {
JOptionPane.showMessageDialog(null,"Error!");
err = true;
}
} while (err);
if (num % 2 == 0) {
JOptionPane.showMessageDialog(null,"Even.");
}
else {
JOptionPane.showMessageDialog(null,"Odd.");
}
do {
input = JOptionPane.showInputDialog("Try again? Press Y for yes or N to go back to main menu.");
again = input.charAt(0);
} while (again != 'Y' && again != 'y' && again !='N' && again !='n');
} while (again == 'Y' || again == 'y');
}
if (choice == 2) {
char letter = 0;
do {
do {
try {
input = JOptionPane.showInputDialog("Character : ");
letter = input.charAt(0);
err = false;
} catch (InputMismatchException a) {
JOptionPane.showMessageDialog(null,"Error!");
err = true;
}
} while (err);
if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i' || letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U') {
JOptionPane.showMessageDialog(null,"Vowel");
}
else {
JOptionPane.showMessageDialog(null,"Consonant");
}
do {
input = JOptionPane.showInputDialog("Try again? Press Y for yes or N to go back to main menu.");
again = input.charAt(0);
} while (again != 'Y' && again != 'y' && again !='N' && again !='n');
} while (again == 'Y' || again == 'y');
}
} while (choice <= 0 || choice > 6 || again == 'N' || again == 'n');
}
Why doesn't the program Odd/Even handle the NumberFormat exception whenever I try to delete the BufferedReader line even though it wasn't
used in the whole program?
I am not able to duplicate this problem. I removed the BufferedReader and option #1 works the same as it did before. I entered integer values, special characters, letters, spaces and it works fine.
How can I reject integer inputs for the Vowel/Consonant program?
You could modify your else condition from this:
else {
JOptionPane.showMessageDialog(null,"Consonant");
}
to this:
else if(Character.isLetter(letter)){
JOptionPane.showMessageDialog(null,"Consonant");
}
else{
JOptionPane.showMessageDialog(null,"Error! You must enter a valid letter.");
}
When I exit the program, the console shows this.
Exception in thread "main" java.lang.NumberFormatException: null at ...
Regarding the NumberFormatException you're seeing, I'm guessing you're pressing the Cancel button on the dialog. When you press cancel the variable input receives the value null. When you try to parse null as an integer it fails and throws the exception:
Exception in thread "main" java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at exception.DoWhileIf.main(DoWhileIf.java:18)
Line 18 is this line: choice = Integer.parseInt(input);
Notice how the exception told us - java.lang.NumberFormatException: null which tells us that the parameter being passed to the parseInt method is null.
Lastly some additional thoughts for you to consider:
Whenever you get input from the user you must account for all the possibilities somehow. For example when you have code like this:
letter = input.charAt(0);
you're not accounting for the possibility that the input could be null or empty in which case this logic will throw an exception.
A concrete example is when the user clicks Cancel on the dialog that asks whether they want to try again:
input = JOptionPane.showInputDialog("Try again? Press Y for yes or N to go back to main menu.");
When the user clicks Cancel on this dialog the same thing happens that I described above regarding the NumberFormatException - input becomes null. If you try to use input like this:
again = input.charAt(0);
it will fail with the exception:
Exception in thread "main" java.lang.NullPointerException
because you can't invoke a method on a null.
Another example is when the user enters nothing at the main menu but simply presses OK. The result is this exception:
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
This happens because input was set to an empty string and parseInt does not know how to convert empty string into an integer value.
Another item I want to bring up is that you're using this same piece of code over and over again. Whenever you have code you want to reuse you should not copy and paste it but instead create a method, object, or other construct so that you can refer to it.
do {
input = JOptionPane.showInputDialog("Try again? Press Y for yes or N to go back to main menu.");
again = input.charAt(0);
} while (again != 'Y' && again != 'y' && again !='N' && again !='n');
Breaking up your logic into smaller more manageable pieces will help you to debug, test, and maintain your code more easily.
Another point I want to touch on regarding this same block of logic is that you're using the same kind of dialog to ask for many different kinds of input. Since you're using a GUI dialog, you could use a dialog that is better suited to your task such as one that asks the user to press either a Yes button or No button.
You can learn more about different kinds of dialogs by reading the How to Make Dialogs Tutorial
Here is an example of how you could create a more friendly dialog:
/**
* Asks the user if they want to try something again and
* returns a boolean representing the user's response.
* #return true if the user answers Yes, false otherwise.
*/
private static boolean promptToRepeatSelectedOption(){
int n = JOptionPane.showOptionDialog(null,
"Try again?",
"Repeat Selection",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
null,
null);
return n == JOptionPane.YES_OPTION;
}
The above method, when invoked, will create and display a dialog with two buttons - Yes and No - and the user will have to select one of them or close the dialog. The logic simply looks for if the user said Yes (by clicking the Yes button) and returns true when that is the case. If the user closes the dialog or chooses the No option the method returns false simply because either of those two scenarios will cause the n == JOptionPane.YES_OPTION comparison to result in a value of false.
You can replace your entire loop with a call to this method like this:
First, define a variable to hold the user's response.
boolean repeat = false;
Then invoke the method and set the variable to its result:
repeat = promptToRepeatSelectedOption();
Now replace the outer loop condition
while (again == 'Y' || again == 'y');
with this: while (repeat);
and finally replace part of the outermost loop condition
again == 'N' || again == 'n'
with this: !repeat
One final thought is that you're using very general error messages when the user enters something incorrect or invalid:
JOptionPane.showMessageDialog(null, "Error!");
It's always better to explain to the user a little bit about what they did wrong so that they know how to avoid the error next time. You should probably consider adding more detail to your error messages.
Hope this helps!
Here is my code:
public static void nameset(){
int no = 1;
name = JOptionPane.showInputDialog(frame, "The last people who still had cake had to defend it with heir lives, No matter the cost.\nOne of those last people, was you. What is your name?", "",1);
if(name.equals("") || name.equals(JOptionPane.CANCEL_OPTION));{
JOptionPane.showMessageDialog(frame,"Please tell me your name. I don't wanna have to exit out of the game about you.","Hey!",1);
no++;
}if (name.equals("") || name.equals(JOptionPane.CANCEL_OPTION)){
if (no == 2){
JOptionPane.showMessageDialog(frame, "Seriously? Again?! that's it..");
if (name.equals(JOptionPane.CANCEL_OPTION)){
System.exit(0);
}else{
System.exit(0);
}
}
}
}
I want it so if you press the cancel option it tell you to restart. But if you press cancel, it shows an error in the console. I think it's the name.equals(JOptionPane.CANCEL_OPTION), But I'm not sure. Is there any reason for it not to work? Thanks in advance for any help.
The cancel button will always result in null being returned. See official JavaDoc:
Returns: user's input, or null meaning the user canceled the input
So your condition should be changed to:
if(name == null || name.equals(""))
and you also need to remove the semicolon after your first if statement! Otherwise the following block will always be executed.
Once that's fixed, your "exit after 3 times no" will not work because you're not actually looping your input dialog.
Try this
int no = 1;
String name = JOptionPane.showInputDialog(null, "The last people who still had cake had to defend it with heir lives, No matter the cost.\nOne of those last people, was you. What is your name?", "",1);
if(name == null || name.equals(""));{
JOptionPane.showMessageDialog(null,"Please tell me your name. I don't wanna have to exit out of the game about you.","Hey!",1);
no++;
}if (name == null || name.equals("")){
if (no == 2){
JOptionPane.showMessageDialog(null, "Seriously? Again?! that's it.."+name);
if (name == null || name.equals("")){
System.exit(0);
}else{
System.exit(0);
}
}
}
I have to write a program making a 2-D array and printing it out. Then I am supposed to guide a "character" through this maze. so I want to make it move Up/Down/Left/Right. The user would be allowed to type in u/U/d/D/l/L/r/R.
I put in so that it would give me an error if one of those was not typed in. However it still gives me an error if it is typed in correctly.
char move;
System.out.println("Which way do you want to move? U/D/L/R");
move=stdin.nextLine().charAt(0);
while(move != 'u' || move !='U') {
while( move != 'd' || move != 'D'){
while( move != 'l' || move != 'L'){
while(move != 'r' || move != 'R'){
System.out.println("Invalid input. Try again.");
move = stdin.nextLine().charAt(0);
}}}}
Try this:
Scanner stdin;
stdin = new Scanner(System.in);
move = stdin.nextLine().charAt(0);;
move = Character.toUpperCase(move);
while(move !='U' && move != 'D' && move != 'L' && move != 'R' )
{
System.out.println("Invalid input. Try again.");
move = stdin.nextLine().charAt(0);
move = Character.toUpperCase(move);
}
Your current code do not make sense. If I type R (for example), this would make the program to enter in infinite loop. Since, all the condition on the upper while would evaluate true. Thus, not reaching the instruction that will ask for another input (stdin.nextLine()).
You may also try the following (does the same thing in a different way).
Along with other field declarations:
private static final String keySet = "uUdDlLrR";
And inside the method:
char move = stdin.nextLine().charAt(0);
while (keySet.indexOf(move) == -1) {
System.out.println("Invalid input. Try again.");
move = stdin.nextLine().charAt(0);
}
It's just a bit more readable and requires little change in case you wish to modify the set of allowed keys.
The syntax is a little bizarre (why "while" and not "if"?.... and why nested?) ... but basically you want to be testing with '&&' not '||'.
In english: you want if input is not A and input is not B, then error. If you do "or" then it will always error because one of those nots will alway be true.
EDIT:
easy mistake to make --- for style/clarity, I'd suggest:
switch (move) {
case 'u': case 'U':
/*up code*/
break;
case 'd'' case 'D':
/*down code*/
break;
case 'l'' case 'L':
/*left code*/
break;
case 'r'' case 'R':
/*right code*/
break;
default:
System.out.println("Invalid input. Try again.");
break;
}