I'm fairly new to java and was wondering how would one force a user to enter a valid option in a do...while loop?
What i'm trying to achieve here is to display a menu for as long as the user does not select the exit option which is '4' in my case (it's a char not an int). But if the selection is invalid I want to display an error message and prompt the user to make a new selection, this time, without displaying the menu again.
So far, inside my do...while loop i'm displaying different information according to the user selection. If they enter anything other than 1-4, they end up in my last else if which displays an error message, but at the same time they leave the if/else if loop and end up back in the main menu.
Don't know if this is clear but any help would be appreciated. I also tried the same thing with switch but got the same problem.
Thanks.
do {
// display main menu
if (menu == '1') { ... }
else if (menu == '2') { ... }
else if (menu == '3') { ... }
else if (menu == '4') { ... }
else if (menu != '4') { // display error message }
} while (menu != '4')
Okay, so you have a job which we can describe in a self-contained fashion with a short list of clearly stated parameters:
Ask the user for input.
Check that the input is valid.
If not, keep asking.
That's it. That's a job we can write. Easily at that.
So, do that! Make a method to do just this job. There's only one parameter you need, which is: "What constitutes valid input". If we can simplify that we just need a character, and everything from '1' to this char is valid, then:
public char askUser(char maxValid) {
do {
char in = askUserForInput(); // however you get that char.
if (in >= '1' || in <= maxValid) return in;
System.out.println("Enter a value between 1 and " + maxValid + "> ");
} while (true);
}
Then you can just call this method when you need input.
You can roll this logic (so, that'd be a do/while loop inside your do/while loop) into the main loop, but two rather significant aspects of writing good code is to find easily isolatable aspects and to, well, isolate them (be it making new methods, types, modules, or subsystems - it applies across the entire hierarchy), and to avoid repeating yourself.
Related
But if I put it to "valid = false;" it does not work in debug or running.
In fact even running the code, I can't type anything after the "Do you want to order anything else?", no matter if it's in debug or running mode.
Am I missing something? After asking "how many you want to order" and you put in a number after it should ask "do you want to order anything else" which is does but then I can't type and break out of the do while loop. Everything else is working up to that point.
do {
boolean itemValid = true;
while (itemValid) {
System.out.println("Please enter an item name: ");
String enterItem = scnr.nextLine();
if (keepTrack.containsKey(enterItem)) {
System.out.println(keepTrack.get(enterItem));
itemValid = false;
} else {
System.out.println("Sorry we don't exist.");
continue;
}
System.out.println("How many do you want to order?");
int enterQuan = scnr.nextInt();
yourOrder = enterQuan;
valid = false;
}
System.out.println("Do you want to order anything else?");
String yesNo = scnr.nextLine();
if (yesNo.equalsIgnoreCase("n")) {
valid = false;
} else
break;
} while (valid);
Two problems with your code. First, probably unnoticed yet:
do ...
if (keepTrack.containsKey(enterItem)) {
System.out.println(keepTrack.get(enterItem));
itemValid = false;
} else {
System.out.println("Sorry we don't exist.");
continue;
}
When your input is "invalid", you turn into the else branch. The else branch continues the loop. The loop depends on value. Thus: as soon as you start with value=true, and then have an invalid input, you end up with a never-ending loop. Because nothing between the loop start and the continue statement will ever change the conditions that would end the loop.
Your actual question: when you call int enterQuan = scnr.nextInt() that does not consume the "ENTER" that you typed on the console. See here for details.
And there is another problem:
if (yesNo.equalsIgnoreCase("n")) {
valid = false;
} else
break;
}
When the user enters n or N, you go valid=false which ends the outer do-while loop. Thus: when the user enters anything else, the elsepath is taken. What is to be found in the else path? A break. Which also ends the do-while loop.
In other words: your code does exactly what you told it to do: to end the do-while loop, one way or the other.
The real answer is: you need to be much more careful what you put in your code. Each and any character matters. And when you put something into your code for an experiment: remember that it is there, and has effects.
The code below is for a simple calculator with the four basic mathematical operators. It is a working program, it works as expected. However, I have a few questions to understand and improve both my program as well as my understanding of Java. (I have used google but the amount of redundant info confuses me and haven't found any perfect answers on StackOverflow too, though there are dozens of related questions. Believe me, I did tried before posting here).
How can I make sure that the user input is exactly and strictly one char?
here in my program, it accepts more than one character (+-*) but operates on the first char (+) only. I want to make sure more than one character is not accepted as input.
After successful execution of the program, how can I somehow let the user repeat the main method? I mean, a user adds two numbers, gets his answer and he wants to do another calculation, maybe multiply two numbers this time. I can ask the user for yes or no to continue but how do I take him/her back to the beginning? (will a loop work? how?)
A the end of the program I used two methods to output a message. The system.out.print works fine but the JOptionPane method doesn't display the message and the program doesn't terminate (I have commented it out). I would like to understand why?
Is the default case required in the switch? And Am I following the correct code structure? (the arrangements and uses of curly braces)
NB: As I said this calculator works fine and can be used by newbies like myself to better understand the concept as I have commented on every detail. Please understand that I couldn't add everything in the question title due to limits...
package mycalculator;
import javax.swing.JOptionPane;
import java.util.*;
public class MyCalculator{
public static void main (String [] args){
// Let us code a simple calculator//
// Variable type declarations//
char OP;
int firstNum;
int secNum;
// Display an explanation of what this program does//
System.out.println("This is a simple calculator that will do basic
calculations such as :"
+ "\nAddition, Multiplication, Substraction and Division.");
// Create a scanner object to Read user Input.//
Scanner input = new Scanner(System.in);
// Ask user to input any positive number and read it//
System.out.println("Enter Any positive number followed by pressing
ENTER.");
firstNum = input.nextInt();
// Ask user to input/decide his choice operator and read it //
System.out.println("Enter a valid OPERATOR sign followed by pressing
ENTER.");
OP = input.next().charAt(0);
// Loop the below statement till one of the four (+,-,*,/) is entered.//
while(OP != '+' && OP != '-' && OP != '*' && OP != '/'){
System.out.println("Please Re-enter a valid Operator (+,-*,/)");
OP = input.next().charAt(0);}
// Ask user for any second number and read it//
System.out.println("Enter your Second number followed by an ENTER
stroke.");
secNum = input.nextInt();
// Various possible Resolution based on OP value.//
int RSum = firstNum+secNum;
int RSubs= firstNum-secNum;
int RPro = firstNum*secNum;
double DPro = firstNum/secNum;
// Conditional statements for Processing Results based on OP and display.//
switch(OP){
case '+': System.out.println("The Resulting sum is "+ RSum);
break;
case '-': System.out.println("The Resulting sum is "+ RSubs);
break;
case '*': System.out.println("The Resulting Product is "+ RPro);
break;
case '/': System.out.println("The Resulting Divisional product is "+
DPro);
break;
//Maybe the default case is actually not needed but is added for totality//
default : System.out.println("Try Again");
break;
}
// The following code maybe deleted, it is for experimental purpose//
// Just checking if additional statements executes after a program
completes//
System.out.println("Test Message ");
// JOptionPane.showMessageDialog(null, "The Process Ends Here!");
//The test message works fine//
//The JOptionPane statement don't work and program doesn't end. WHY?//
}
}
How can I make sure that the user input is exactly and strictly one
char? here in my program, it accepts more than one character (+-*) but
operates on the first char (+) only. I want to make sure more than one
character is not accepted as input.
If you use console application and Scanner, only thing that you can do is read a String and check its length. In case you use Swing, you could implement KeyPressListener and proceed exactly after user press a button (but not for console application).
After successful execution of the program, how can I somehow let the
user repeat the main method? I mean, a user adds two numbers, gets his
answer and he wants to do another calculation, maybe multiply two
numbers this time. I can ask the user for yes or no to continue but
how do I take him/her back to the beginning? (will a loop work? how?)
You can't repeat main method. In Java main method is been executing only once. To repeate your code, you could wrap whole main method content to the infinite loop or move the content to the separate method and call it from the loop in the main method.
A the end of the program I used two methods to output a message. The
system.out.print works fine but the JOptionPane method doesn't display
the message and the program doesn't terminate (I have commented it
out). I would like to understand why?
JOptionPane works only for graphic application (Swing/AWT). This is not available in console. You have only standard input and output there.
Is the default case required in the switch? And Am I following the
correct code structure? (the arrangements and uses of curly braces)
No, default case is optional by JVM syntax. I remember, that e.g. in C++ there was reccomendation to place it (event empty), to exclude side effects of compilators. I do not know, is there such reccomendation in Java, but when I use switch, I prefer to always add it to exclude logical problem (but this is definetly optional according to syntax case). You use switch correctly.
public static void main(String[] args) {
System.out.println("This is a simple calculator that will do basic calculations such as :"
+ "\nAddition (+)"
+ "\nMultiplication (*)"
+ "\nSubtraction (-)"
+ "\nDivision (/)");
System.out.println();
try (Scanner scan = new Scanner(System.in)) {
while (true) {
System.out.println("Enter Any positive number followed by pressing ENTER.");
int first = scan.nextInt();
System.out.println("Enter a valid OPERATOR (+,*,-,/) sign followed by pressing ENTER.");
String operator = scan.next();
while (operator.length() != 1 || !"+*-/".contains(operator)) {
System.out.println("Please Re-enter a valid Operator (+,-*,/)");
operator = scan.next();
}
scan.nextLine();
System.out.println("Enter your Second number followed by an ENTER stroke.");
int second = scan.nextInt();
if ("+".equals(operator))
System.out.println("The Resulting sum is " + (first + second));
else if ("*".equals(operator))
System.out.println("The Resulting mul is " + (first * second));
else if ("-".equals(operator))
System.out.println("The Resulting sub is " + (first - second));
else if ("/".equals(operator))
System.out.println("The Resulting div is " + ((double)first / second));
System.out.println();
System.out.println("Do you want to exit ('y' to exit)?");
if ("y".equals(scan.next()))
return;
System.out.println();
}
}
}
1) you can check size of string input.next() .If it is one then continue else again prompt for operator choice .
2)I would suggest better create a different method and put all logic in it and call it the number of time you want or call infinite number of times.
4)Should switch statements always contain a default clause?
I have a registration page where the user has to enter personal information about themselves, if something entered is invalid then error notifications should pop up
if (!PhoneNumber.startsWith("055") || !PhoneNumber.startsWith("050") || !PhoneNumber.startsWith("056") || !PhoneNumber.startsWith("052")) {
// does not match
contact_number.setError("Please enter a valid phone number");
return;
}
if (TextUtils.isEmpty(password) )
{
VendorRegPassword.setError("Please enter your password");
return;
}
else if (password.length() < 6)
{
VendorRegPassword.setError("Please use more than 6 characters");
return;
}
if (TextUtils.isEmpty(email) || !email.contains("#") )
{
VendorRegEmail.setError("Please enter a valid email address");
}
Independently they work on their own but when put together it does not work properly, also the phone number error does not work properly, can somebody help me with this?
The other answer is correct; the return statement simply prevents all checks to be executed. And in this case, you want all validations to take place, as each validation has a different way of informing the user about the problem.
Beyond that: from a "clean code" perspective you should be careful to simply stuff all validations into the same poor method. Instead: structure your code so that it clearly expresses what is going on, like:
private void validateAll(PhoneNumber number, Email email, Password password) {
validatePhoneNumber(number);
validateEmail(email);
...
and separate helpers like
private void validatePhoneNumber(number) {
boolean validPrefix = false;
for (String validPrefix : PREFEIXES) {
if (phoneNumber.startsWith(validPrefix) {
validPrefix = true;
}
}
if (!validPrefix) {
contact_number.setError("Please enter a valid phone number");
}
}
for example. And please note - I fixed another bad practice (your idea to simply hard-code all valid prefixes). You always want to put such information into some constant set/list; so that you have exactly one place in your code that knows what those prefixes are.
They are not working together properly because you are returning from the method in if or else ifconditions. Remove return statements from if and else. Because return will terminate the execution of method, so further code will never be executed due to return.
They are working separately because, there is no need to execute further conditions (no further conditions at all), so returning from method seems correct solution.
Now I know that there is a thread called "Validating input using java.util.Scanner". I already looked there and that thread only answered 1/2 of my problems. The other half is when someone enters a number greater than 2 I get Array Index Out of Bounds Exception. I just need help on if someone enters a 3 for either row or column, the console should prompt something like this:
"Enter the coordinates to place an 'X'. Row then Column."
//enters 3 and 3
"Please enter a valid input"
It would keep and asking the user for a valid number until he gives one.
Would I need to do something like the !keyboard.hasNextInt() but for integers? And that would run smoothly with the rest of my code?
You could use a do-while loop. Something like
do {
//prompt
//input
} while (input not valid);
Where prompt and input should be replaced by code to prompt the user and accept input. In the while section, check if input is valid.
You're question isn't too clear but I'll try to make sense of it.
I'm assuming you've named your scanner "keyboard"
Before I try running this code, the first problem I can see is this (Note that I grabbed this from your code before you edited the question):
while (board[row][col] != ' ')
{
System.out.println("Already occupied space");
System.out.println("Choose again");
row = keyboard.nextInt();
col = keyboard.nextInt();
}
Earlier, you made sure that the user enters integers. However, you have abandoned that completely in this case.
Assuming you're trying to avoid an error if the user enters something other than an integer, this is what I would do:
while(true){
boolean valid = true;
if(!keyboard.hasNextInt()){
valid = false;
keyboard.next();
}
else{
row = keyboard.nextInt();
}
if(!keyboard.hasNextInt()){
valid = false;
keyboard.next();
}
else{
col = keyboard.nextInt();
}
if (valid && (row > 2 || col > 2)){
System.out.println("Please enter a valid input");
continue;
}
else if(!valid){
System.out.println("Please enter a valid input");
continue;
}
else
break;
}
There are a couple reasons this code might seem a bit long. First off, we're trying to test if the input is an integer before we attempt to store it as an int. Secondly, we want to compare the input after we store it successfully to see if it's less than 3. If the input isn't an integer, the boolean "valid" will be false. The way a compiler works, if valid is false in the if statement it will ignore anything to the right of the &&, avoiding an error.
I admit, this is using some commands that I haven't learned before, so this might not be the most efficient way. But you get the idea :)
P.S. You should probably throw the above code into a method.
I'm trying to write a program where the run method calls a predicate method that asks someone "Do you want to go to a movie tonight?". If the user enters "yes" to the question I want the program to say "Ok. Let's go tonight." If the user enters "no" I want the program to print "That's cool lets go next week." But if the user enters "maybe" I want my program to say "it's a yes or no question" then ask the question again "Do you want to go to go to a movie tonight? " and then wait for a user to enter a response again. The problem I' having is if the user enters "maybe" the program says "it's a yes or no question" then automatically prints "that's fine lets go next week." How do i fix this incorrect logic in my program? This is a question in the chapter focusing on parameter passing in my book. Did I correctly design my program to pass the string value from the run method to the isYesorNo method for what I'm trying to write?
import acm.program.*;
public class MoviesTonight extends ConsoleProgram {
public void run() {
String answer = readLine("do you want to go to a movie tonight?");
if (isYesorNo(answer)) {
println("Ok. Let's go tonight");
} else
println("that's cool let's go next week");
}
private boolean isYesorNo(String response) {
while (!response.equals("yes") && !response.equals("no")) {
println("it's a yes or no question");
break;
}
return (response.equals("yes"));
}
}
I would use a enum for returning the answer if you want something other than true/false, but still a discrete set of values.
For example:
enum Answer {
YES,
NO,
MAYBE
}
Then switch on the enum instead of if/else (down to personal preference, I think a switch statement is cleaner), putting all in a while loop:
boolean yesOrNo = false;
while (!yesOrNo) {
Answer answer = readAnswer("do you want to go to a movie tonight?");
switch (answer) {
case ANSWER.YES:
println("Ok. Let's go tonight");
yesOrNo = true;
break;
case ANSWER.NO:
println("that's cool let's go next week");
yesOrNo = true;
break;
default:
println("it's a yes or no question");
break;
}
}
So basically if the answer is MAYBE, yesOrNo doesn't get set to true so the while loop is executed again when the condition is checked.
The readAnswer method should be a private static helper method and return the correct enum value based on the input string. Either do this by using an if/else or switch statement on the string.
Two things here:
The logic is wrong. If the input is "maybe", then your isYesOrNo will print out "it's a yes or no question", but then returns false, which gives the additional (problematic) output ""that's cool let's go next week".
The break in the loop does not make sense, which is the real problem. The loop should continue unless the condition is meet, it should break out on the first execution of the loop.
In addition to the suggestions already provided, the isYesOrNo method contains a significant error, which is in fact the answer to your base question:
The problem I'm having is if the user enters "maybe" the program says "it's a yes or no question" then automatically prints "that's fine lets go next week." How do i fix this incorrect logic in my program?
return (response.equals("yes"));
If the response is 'maybe', then it does not equal 'yes', and the return will be false -- this is why it immediately prints, "that's cool let's go next week". That is in fact the 'else' condition you supplied for if(isYesOrNo(answer)).
As it stands, you're checking to see if the response is yes/no, starting a while loop which runs if it isn't yes/no, breaking the while loop prematurely, and then returning false on one of the conditions which spawned the while loop in the first place (read: not 'yes'), which finally gets handled as a 'no' (which may not be the case).
Try something like the following, if you want to use if-else:
public void askQuestion(){
String response = readline("Do you want to go to a movie tonight?");
getYesNoResponse(response);
}
public void getYesNoResponse(String answer){
if (answer.equals("yes"){
//print the yes response
} else if (answer.equals("no") {
//print the no response
} else {
askQuestion();
}
}