I am trying to store a value inside a variable depending on the input:
switch(pepperoni) {
case 'Y':
case 'y':
topping1 = 1;
break;
case 'N':
case 'n':
topping1 = 0;
break;
default:
{
System.out.print("This is not a valid response, please try again \n");
System.out.print("Do you want Pepperoni? (Y/N): ");
pepperoni = scan.next().charAt(0);
break;
}
I want the variable topping1 to store the value 1 if the input is 'Y' or 'y' and to store the value 0 if the input is 'N' or 'n'
If the input is neither 'Y', 'y', 'N' nor 'n' then I want it to repeat the question until a valid input is typed in.
The problem arises when I later in the program try to print the value 'because it might have not been initialized', which somewhat makes sense. (example below)
if(topping1 > 0)
System.out.println("Pepperoni");
// 243: error: variable topping1 might not have been initialized
I do realize there are other ways to do this, but as I am really wanting to learn Java I try to understand as much of the fundamentals as possible. Therefore would I be really happy if someone could tell me why this not work and if there is a way to do this with a switch statement or quick fixes.
The issue probably is that the switch statement does not guarantee a value set for topping1. If you received a response of 'L' you would neither set it to 1 or 0. You should set a default value when you initialize topping1 or set one in the default clause.
Java's compiler can't analyze your code to know that you won't let people out of the loop (that I presume this is in) until it's set. It can only tell that there's a path through the code which would allow it to not be set.
This works (same would be true for switch):
int a;
if (condition()) {
a=0;
} else {
a=1;
}
System.out.println(a);
And this works:
int a=1;
if (condition()) {
a=0;
}
System.out.println(a);
This does not:
int a;
if (condition()) {
a=0;
}
System.out.println(a); // compiler error!
because if condition() returns false, a is undefined. Local variables must be defined. Note that this is different than fields on classes which automatically are assigned default values of null, 0 or false.
If pepperoni is not Y, y, N, or n, you never assign a value to topping1, because the default case never assigns it a value. E.g., if pepperoni is not one of those four values, then the flow of control skips the other two cases and goes to default, which never gives topping1 a value, so later when you try to use it, it's possible topping1 has never received a value at all.
The "workaround" is to correct the logic so that you never try to use topping1 without having assigned it a value. How you do that depends on logic you haven't shown us. You might assign it a value other than 0 or 1 (the values you assign in the other branches of the switch), for instance.
You are getting the "might not have been initialized" error because there is a path through your switch statement in which you don't initialize topping1 and you reference the variable later.
What you can do: Initialize topping1 to an invalid value (say, -1). Then place your case statement in a while loop that checks if the value of topping1 is still equal to -1.
Then, once you are out of the while loop, you know that the following are true:
You have intialized topping1, so no compiler error should result.
You have a valid value for topping1.
This looks a little ugly, but writing the loop like this is one way to stop the compiler complaining:
for (;;) {
System.out.print("Do you want Pepperoni? (Y/N): ");
pepperoni = scan.next().charAt(0);
switch (pepperoni) {
case 'Y':
case 'y':
topping1 = 1;
break;
case 'N':
case 'n':
topping1 = 0;
break;
default:
System.out.println("This is not a valid response, please try again");
continue;
}
break;
}
Related
What I am trying to accomplish: when the user types in anything other than 1 or 2, there will be a prompt saying "I don't understand you" and it would ask the user to choose 1 or 2 again without having to run the program each time.
Something like this:
do {
String a = input.nextLine();
num = Integer.parseInt(a);
switch (num) {
case 1:
System.out.println("hello");
break;
case 2:
System.out.println("goodbye");
break;
default:
System.out.println("I don't understand you");
}
} while (num == default);
I know typing this will give me an error, so how do I compare it?
First, you have a potential infinite loop because the value for num which controls the stoping condition is never updated inside the loop.
Second, you could introduce a local variable to track when the user input was understood and exit the loop on that condition:
boolean understood;
do {
understood = false;
String a = input.nextLine();
int num = Integer.parseInt(a);
switch (num) {
case 1:
System.out.println("hello");
understood = true;
break;
case 2:
System.out.println("goodbye");
understood = true;
break;
default:
System.out.println("i dont understand u");
break;
}
} while (!understood);
What you asked is technically a while(true) since everything which is not 1 or 2 is default. Also you should probably put your scanning bit in the loop.
If you try to check if value is different from 1 and 2 to ask again for a valid option:
do
{
// stuff
}
while( num != 1 && num != 2)
Since "default" is a keyword you just can not compare it to anything. It's meaningless though, because in your condition you used all possible cases(case 1 and case 2), so your code will never end, printing either "hello" or "goodbye" forever.
These are all possible commands I want to accept.
Q
H
A
D
L <Color> <Drawer>
M <Drawer1> <Drawer2>
I have this switch case. What is the best method to error check the input/ where is the best place to scan for potential non-single letter commands like 'L' or 'M' commands? I would like to have only one default case in the code, to avoid copy-pasting the error message in more than one place. Also, I'm worried about commands like Q zzzzz being accepted, since I am only calling reader.next() which reads until the next whitespace. Should I be using reader.nextline() instead?
String input = reader.next();
switch (input.toUpperCase())
{
case "Q": //Quit:
//.....
break;
case "H": //Help:
//.....
break;
case "A": //About:
//.....
break;
case "D": //Draw:
//.....
break;
case "L": //Lay:
//prompt for more input here?
//if so, and the input is wrong, how to jump to default?
//.....
break;
case "M": //Move:
//same issue as 'L'
break;
default:
System.out.println("\nYour command was not recognized. Type H for help.");
}//end switch()
I originally thought to scan three times before the switch case (2 of them might be empty if user chooses a single-letter command).
I can code a solution, but it would be a very ugly one. I am just a beginner programmer trying to write things elegantly.
Maybe something like this:
String input = reader.nextLine();
char c = input.charAt(0);
if ( (c != 'M' && c != 'L') && input.length() > 1)
// throw some error message
switch(c)
...
case "L": //Lay:
// parse the rest of input here
break;
Assume we enter the command L red hi (for some reason if i put text inside <> it disappears, even with quotes "")
You can use something like this in the default case:
input.matches("^[L-M] <\\w*> <\\w*>$")
This will check for the right formatting. Then you can continue checking with:
input.substring(3, 6).equals("Red")
And finally:
input.substring(9, 11).equals("Hi")
Note that the first number in the substring command is the first letter of the command (right after '<') and the second number is the closing '>'. 'L' is 0, making 'R' 3, and the first '>' 6.
The complete code for this situation is as follows:
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
System.out.print("Enter the letter: ");
String input = reader.nextLine();
switch (input.toUpperCase())
{
case "Q": //Quit:
//.....
break;
case "H": //Help:
//.....
break;
case "A": //About:
//.....
break;
case "D": //Draw:
//.....
break;
default:
if(input.matches("^L <\\w*> <\\w*>$")){
// Use the below if-else statements for all L <text> commands
if (input.substring(3, 6).equals("Red")){
if (input.substring(9, 11).equals("Hi")){
// Do stuff
/* Note: the first number is counting from 0 to the first letter
* of the sub-command (H) in the following:
* L <Red> <Hi>
* It comes out as 9
* The second number (11) is the closing sign thing (>)
* You will need to modify these according to your commands
*/
}
// Use else-if statements for different secondary commands
else
System.out.println("\nYour command was not recognized. Type H for help.");
// You can replace this error message with a boolean value, or a method
// To avoid the message appearing in the code more than once.
}
// Use else-if statements for different commands
else // Final else command
System.out.println("\nYour command was not recognized. Type H for help.");
}
// After the different commands, the next else-if is to check for
// M <Stuff> <Stuff>
}//end switch()
}
Hope this helps!
Ok, so the code below loops wonderfully. It can loop as long as it wants to. The thing is though, I can never get out of the loop. I'm trying to build a text-adventure, by the way for those wondering, but I really need to get out of this loop.
System.out.println("\n\nWelcome, " + name + "! To proceed, enter your class of fighter.");
System.out.println();
boolean x = true;
while (x){
//information print statements
System.out.println("What will your class be? ");
String heroclass = scan.nextLine();
heroclass.toLowerCase();
String A;
switch (heroclass)
{
case "slayer": A = "You have selected the Slayer class.";
break;
case "blader": A = "You have selected the Blader class.";
break;
case "bandit": A = "You have selected the Bandit class.";
break;
case "wizard": A = "You have selected the Wizard class.";
break;
default: A = "Invalid entry.";
break;
}
String killloop = A;
if (killloop.charAt(0) == 'Y'){
x = false;
}
}
You need to assign heroclass.toLowerCase(); to the original value of heroclass:
heroclass = heroclass.toLowerCase();
If you do not do this, the lowercase version of heroclass is not saved.
heroclass is of String type. String is immutable type of object, so you can't update this string. heroclass.toLowerCase() just return another String object with lower cased characters, so you need to reassign this string result to this variable:
heroclass = heroclass.toLowerCase();
Put your loop in a labeled block:
myblock: {
while (true) {
//code
heroclass = heroclass.toLowerCase();
switch(heroclass)
{
case "slayer": A = "text";
break myblock;
//repeat with other cases
}
}
}
//goes to here when you say "break myblock;"
What you're doing is basically assigning the label myblock to the entire loop. When you say break myblock it breaks out of the entire section inside of the brackets.
NOTE: I would recommend this solution over the others because it doesn't depend on the magic value assigned by the switch; it works no matter what it is.
Also, I've added the part to make it case insensitive. Sorry about the confusion!
Although coding wombat is right, i'm not a big fan of the way you did things here. A loop around your whole program like this isn't good practice. It's super clunky and will lead to many problems, not to mention you're making things more complicated for yourself. Ideally you'd want to put this class selection part of the program inside a method. Then if the user's input is invalid, simply call back the method recursively until you get correct input.
Ex.
case A: do this...
case B: do this...
case C: System.out.println("Not a valid input);, classSelector();
Also, when you use OOP you have the benefit of storing all the player's attributes inside an object, as well as making methods that manipulates those attributes. It will make your code a lot cleaner and easier to work with.
Ex.
Player1.heal(10);
This is a follow up to a question I have asked previously that did get answers that should have fixed my problem, but unfortunately did not. My program reads in a text file and organises data before giving the user a number of options. When the program gets to this point I want to user to be able to select an option, that performs an operations, but then returns the user back to the start point to be able to perform more operations. This is the answer I liked best (thanks to Octopus) and am currently trying to implement.
//set choiceentry to -1, this will make it to enter while loop
int choiceentry = -1
while(choiceentry < 1 || choiceentry > 3){
System.out.println("Enter \"1\", \"2\" or \"3\"");
if(scanchoice.hasNextInt())
choiceentry = scanchoice.nextInt();
switch(choiceentry){
case 1:
//do logic
break;
case 2:
//do logic
break;
case 3:
//do logic
break;
}
}
As I see it, the program should enter the loop initially, allow the user to input a selection, then return back to "enter a value". However, the program does not return, and terminates after one operation. How can I prevent this to continue the program running infinitely?
Thanks in advance!
The current while loop is there to get valid input -- don't change it.
You need to wrap this code in another while loop that loops til a sentinal value is entered.
while (!isSentinalValue) {
while (inputNotValid) {
// get valid input
}
}
Edit
More specifically in pseudocode:
while (!isSentinalValue) {
input = invalidValue
while (inputNotValid) {
getInput
}
use input to do menu things
}
So I would not have the switch block inside of the inner loop, since that loop concerns itself only with making sure that the input entered is valid. Do the switch block outside of the inner loop, and be sure to set the sentintal value that allows the user to escape the outerloop when appropriate.
Your while(choiceentry < 1 || choiceentry > 3) condition is wrong. If you want it to loop , then you have to make it between 1 and 3 .
So this also means that you will have to change your choiceentry initialization value. This will work.
int choiceentry = 1
while(choiceentry >=1 && choiceentry <= 3){
System.out.println("Enter \"1\", \"2\" or \"3\"");
if(scanchoice.hasNextInt())
choiceentry = scanchoice.nextInt();
....
}
your loop only runs while choiceentry is less than 1 or greater than 3. As soon as the user enters one of those values, the loop exits.
Learn to use a debugger.
place the following code after switch
if(choiceentry == 4){
break;
}
Now when you will input 4 then it will be terminated, you can use any value other then 4
Use break only when user wants to quit(Say when choiceentry=0). You can use "continue" to make loop infinite. Sample code is given for reference
int choiceentry = 1; // can set any int value except 0 (exit code is 0 for this example)
Scanner scanchoice = null;
while (choiceentry != 0) {
System.out.println("Enter \"1\", \"2\" or \"3\" ..Press 0 to quit");
scanchoice = new Scanner(System.in);
if (scanchoice.hasNextInt())
choiceentry = scanchoice.nextInt();
// System.out.println("choiceentry=" + choiceentry);
switch (choiceentry) {
case 0:
{
System.out.println("Bye Bye");
break;
}
case 1:
{
System.out.println("In Case 1");
continue;
}
case 2: {
System.out.println("In Case 2");
continue;
}
case 3: {
System.out.println("In Case 3");
continue;
}
}
}
I don't think my switch statement is doing anything with my code, I'm new to java so I'm not sure how to use a switch statement in a while loop. I'm trying to take each grade/credit entered so I can find the GPA, but I added a System.out.print for the grades and it says it's worth 0 no matter what gets entered. Please help!
package exercises;
import java.text.DecimalFormat;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
public class GPA_Calculator {
public static void main(String[] args)
{
String greeting = "Hello, this program will calculate your GPA. You will be asked \n"+
"to enter your letter grade for each class, then you will be asked to enter \n"+
"the corresponding number of credits for that class. Once all the grades and credits\n"+
"have been entered, the program will display your GPA.";
JOptionPane.showMessageDialog(null,greeting,"Greeting - Introduction",1);
char gradeEntered;
String grade = "";
String creditEntered = "";
String inputGrade = "";
String inputCredit = "";
String enterGradePrompt = "Enter your letter grade (A, B, C, D, F)\n"+
"Enter Q to display your results\n\n";
String enterCreditPrompt = "Enter the credit hours for your course (0, 1, 2, 3, 4, 5, 6)\n"+
"Enter Q to display your results\n\n";
int points = 0, sum = 0, credits = 0, gradeCount = 0;
while(!inputGrade.toUpperCase().equals("Q"))
{
inputGrade = JOptionPane.showInputDialog(null,enterGradePrompt,"Enter grade",1);
gradeEntered = inputGrade.charAt(0);
grade += inputGrade.toUpperCase()+"\n";
inputCredit = JOptionPane.showInputDialog(null,enterCreditPrompt,"Enter grade",1);
creditEntered += inputCredit+"\n";
if(inputCredit.toUpperCase().equals("Q"))
continue;
credits = Integer.parseInt(inputCredit);
credits++;
switch (gradeEntered){
case 'A': points = 4;
break;
case 'B': points = 3;
break;
case 'C': points = 2;
break;
case 'D': points = 1;
break;
case 'F': points = 0;
break;
}
sum += gradeEntered;
gradeCount++;
}
// Prevents "Q" from being printed in results
grade = grade.substring(0,grade.length()-2);
creditEntered = creditEntered.substring(0,creditEntered.length()-2);
DecimalFormat df = new DecimalFormat("#.##");
double gpa = sum / gradeCount;
String results = "The courses you entered are:\n\n"+
"Grade "+"Hours \n"+
grade+" "+creditEntered+"\n"+
"Resulting in a GPA of "+df.format(gpa)+"\n\n"+
"This program will now terminate!";
JOptionPane.showMessageDialog(null, new JTextArea(results),
"results from the Invitation list generator",1);
}
}
The problem is that your switch statement is checking the value of grade, but your input is stored in inputGrade. The former is never reassigned from the empty string, so points never gets incremented.
EDIT: To expand on the comment below:
the conditional in either a while or do/while loop isn't being checked. You're checking it inside the loop and breaking out, which is fine, as you can just make an infinite loop and let the break terminate it. However, it shouldn't be duplicated in the loop conditional.
You should do check that condition early. There's no sense in performing anything inside the loop if the user enters 'q' (also, then, you don't have to have the part where you try to strip it afterwards).
Also, you should always try to keep your variables as locally as possible. There's no need to have anything but the aggregators (totalXxx and yyyEntered in this case) outside of the loop. It just makes it confusing for you in this case, as it's masking the source of your problem. When the switch statement hits the first time, it checks the empty string. The second time, it checks the first string. When you hit 'q', it breaks, and skips your last input. If these input variables were declared inside the loop, that would be immediately apparent.
Finally, while I'm here, you have an error in your gpa calculation. The points per score should take the weight of credits as a positive, not a negative. Something like:
sum(grade * credits) / sum(credits)
I can post fixed code if you want, but since I suspect this is an academic exercise, it would be more beneficial if you came to the solution yourself.
Your switch statement is using grade which seems to be never written to. It's always "".
You get inputGrade, but you don't write to grade itself.
As it is always "", you always get nothing from your switch
You are appending each grade to your gradeEntered
gradeEntered += inputGrade.toUpperCase()+"\n"; // at a point this is something like A\nB\nC\nD\nE.... so it will not match anyway
switch (gradeEntered) {
case "A": points = 4;
break;
case "B": points = 3;
break;
case "C": points = 2;
break;
case "D": points = 1;
break;
case "F": points = 0;
break;
}
so most of the times it will not match to any of your cases.
Either you have to have a separate char for grade and use it in the switch or first use switch and then append it to your variable
You are adding a newline ("\n") to your input, (inputGrade.toUpperCase()+"\n";) so none of your cases are valid.
That is, "A" does not equal "A\n"
I think you should not use "gradeEntered" and instead use:
switch (inputGrade.toUpperCase())
especially since after running the loop more than once, your "gradeEntered" string will start to look like this: "A\nB\nF\nQ\n", which is very far removed from all your cases.
Also, switching on strings is not good practice - it is a newish development in java, and won't be supported by computers running older versions fo java - though for your own use, if the compiler doesn't complain then it is fine. Still, better to get in the habit of switching on chars or ints, since most other programming languages won't let you switch on strings.