How to properly use a switch statement in while loop - java

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.

Related

Why isn't my output showing after my switch statement

I'm learning Java right now and I've never used switch statements before. I tried to enter a simple charmed quiz, but something in the switch statement isn't working.
I've tried putting text at various points in the program to test if the program every reaches that code. I have a good response inside the actual switch, so If I answer Question 1 wrong the text prompt will show up. But any later than inside the switch statement and none of my scoring output appears until all iterations of the for loop are complete. I have tried moving the "correct/incorrect" output to various points and none of them seem to work.
Scanner myScanner = new Scanner(System.in);
System.out.println("Enter your name!");
String name = myScanner.nextLine();
int wrongCounter = 0;
boolean correctChecker = false;
int score = 0;
String answer;
System.out.println("Welcome to the Charmed Quiz, " + name + "!");
for (int i = 0; i < 10; i++) {
if (wrongCounter < 4) {
switch(i) {
case 0:
System.out.println("Who read the spell that gave the Charmed Ones their powers?");
System.out.println("Enter your answer");
answer = myScanner.nextLine();
switch (answer) {
case "Pheobe":
correctChecker = true;
break;
default:
correctChecker = false;
break;
}
case 1:
System.out
.println("Who travelled to a cursed town with Prue when Pheobe was shot in a premonition?");
System.out.println("Enter your answer");
answer = myScanner.nextLine();
switch (answer) {
case "Cole":
correctChecker = true;
break;
default:
correctChecker = false;
break;
}
}
if (correctChecker == true) {
score++;
System.out.println("Correct!");
} else {
wrongCounter++;
System.out.println("Incorrect!");
}
This definitely isn't the best way of achieving a quiz game, but if you're using this as a learning exercise then the best course of action is to take the advice from #rzwitserloot.
Add a break after your main switch statement cases as opposed to the inner switch statement.
There is no real use having an inner switch statement though when you can use correctChecker = "Pheobe".equals(answer); to get a true or false boolean value in a single line.
This just means you can avoid the second switch statement which makes it way less confusing.
Altogether your cases could look something like this:
case 0:
System.out.println("Who read the spell that gave the Charmed Ones their powers?");
System.out.println("Enter your answer");
answer = myScanner.nextLine();
correctChecker = "Pheobe".equals(answer);
break;
}
In future, it would be better to store questions and answers in an array and use the for loop to iterate through that. This is a good tutorial on the subject.
Good luck with the rest of your project!
There are many, many problems with this code. The primary issue is that break breaks the closest construct it can break, which in your case is the inner switch. Whereas your intent is clearly to break out of both. Either [A] add another break right before the case 1: statement, or [B] use a labelled break; put something like outer: before the first (primary/outer) switch, and then make all those statements break outer;.
But, really, none of this (either the outer or the inner) are in any way sensible in switch form. I get that this is a learning exercise, but I'd think of something else to learn with.
Also, it's Phoebe, not Pheobe.

How do I keep looping in a do-while loop as long as the default part of a switch triggers?

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.

I don't know how to leave this looping structure

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);

Could I have some guidance on introducing methods into my wages program?

I am a little stuck. I have grasped the concept of methods; understanding their purpose but still unsure on how to code it. Below is part of my code I kindly need guidance on. I am trying to create a method which can hold roles and depending on which switch option is selected it will return the the amount. I have four employment roles which all have different payscales. I have commented the errors on the role method. If I can correct this and make it work then I can complete this program :)
import java.util.Scanner;//allows input from the keyboard
import java.text.*;
class Wage_Method_2
{
public static void main(String[]args)
{
Scanner input = new Scanner(System.in);
DecimalFormat fmt = new DecimalFormat("0.00");
double normHrs = 0, overHrs = 0, bonusHrs = 0, actualHrs = 0, cash=0, overPay =0, bonusPay = 0, grossWage = 0,vat23 = 0, netWage =0;
String empName,nextEMP = "y", manager, superVisor, teamLead, general;
while (nextEMP.equalsIgnoreCase("y"))
{
System.out.print("Please enter an employee's first name: ");
empName = input.next();//their name
System.out.print("Please enter "+empName+"'s employment ID: ");
int job = input.nextInt();
System.out.print("Please enter their total hours worked: ");
actualHrs = input.nextDouble();
double basicPay = rate (5.75)*actualHrs;
System.out.println("Basic Pay: "+basicPay);
System.out.println("\nWould you like to log hours for another employee?");
nextEMP = input.next();
if (nextEMP.equalsIgnoreCase("n"))
{
System.out.println("Thank you, the hours have been successfully logged.");
}
}// end of whileloop
}// end of class
public static double rate (double cash String jobrole)// when compiling these errors appear: error: ')' expected and error: <identifier> expected
{
switch (jobrole)
{
case 1:
cash = 5.75;
case 2:
cash = 5.75*1.1;
case 3:
cash = 5.75*1.25;
case 4:
cash = 5.75*1.42;
break;
}
return (cash);
}
}// end of program
There are a few errors here:
The parameter list must be separated by commas
You cannot switch with a String and have the values be integers. (Also note switching on strings was first introduced in Java SE7.)
You don't break out of the switch statement. (This isn't a compile time error, but almost definitely a runtime error, that is the code isn't doing what you expect.)
.
public static double rate (double cash, String jobrole)
// ^
{
switch (jobrole)
{
case "1": return 5.75;
case "2": return 5.75*1.1;
case "3": return 5.75*1.25;
case "4": return 5.75*1.42;
default: return 0; // some default.
}
}
Others have stated that the method has to be in a class. It is. The comments in the code is just wrong. The error you are getting on the line is because you don't have the comma.
In your code, you never break out of the switch. In a switch statement, execution falls through from case to case, so if the value of jobrole is "3" then your code would execute:
cash = 5.75*1.25;
cash = 5.75*1.42;
break;
So to fix this, we just return the value instead of setting a local variable. Another option would be to just break; after each case.
Also note, in this scenario, you don't really need to pass the value cash in, since it is never used anyway (it is just overwritten).:
public static double rate( String jobrole )
{
//...
}
You need to define a method inside your class, not outside it. Move it inside the outer closing curly bracket.
There are a number of other problems in your code as well.
I recommend getting an IDE like Netbeans, they are a free download and the syntax highlighting and inline error reporting will make your life much easier. I suggest Netbeans as it is one of the most intuitive to use, you can also consider other options such as Eclipse though.
Load the file into the editor and look at each of the errors in turn. Google them and find out what they mean, then try and correct them.

Switch statement resulting in java:240 (might not have been initialized)

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;
}

Categories