case expressions must be constant expressions gameDevelopment - java

I have an assignment to build a game bord...
I want the user to put the in program the keys he wants to play with.
The problem is that Java requires that the values ​​in the switch case will be const...
The idea is to create a type inheritance to the KeyListener and then I just add it to his proper player.
the desired Keys are received as a parameter int[] keys
I've seen some people offering a solution for similar problems by adding "static final" unfortunately it does not help
here is my code :
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class PlayerKeyListener implements KeyListener
{
int[] keys;
int playerID;
PlayerKeyListener(int[] keys, int playerID)
{
this.keys = keys;
this.playerID = playerID;
}
public void keyPressed(KeyEvent e)
{
System.out.println("keyPressed code : "+ e.getKeyCode());
switch (e.getKeyCode())
{
case keys[KeyboardSettings.UP]: gameBord.players[playerID].moveUp(); break;
case keys[KeyboardSettings.DOWN]: gameBord.players[playerID].moveDown(); break;
case keys[KeyboardSettings.LEFT]: gameBord.players[playerID].moveLeft(); break;
case keys[KeyboardSettings.RIGHT]: gameBord.players[playerID].moveRight(); break;
case keys[KeyboardSettings.BOMB]: gameBord.players[playerID].addBomb(); break;
default: gameBord.players[playerID].face = 0;
}
e.consume();
}
public void keyReleased(KeyEvent e)
{
System.out.println("keyReleased code : "+ e.getKeyCode());
gameBord.players[playerID].move = false;
gameBord.players[playerID].pic = 0;
e.consume();
}
public void keyTyped(KeyEvent e)
{
System.out.println("keyTyped code : "+ e.getKeyCode());
e.consume();
}
}
tnx ;)

Case expressions must be constant expressions.
You answered yourself in the title. You can't have a variable after case keyword.
The way how switch command works is that all the cases (the values after the case keyword) must be known in compile-time.
switch (e.getKeyCode()) {
case constant1: commands;
case constant2: commands;
}
keys[KeyboardSettings.UP] is not a constant, it is a variable. Its value is known in run-time. The compiler does not know what value is there and is shouting at you: "Hey, user3142930, I need to know the value of everything which follow the case keyword!"
In your case you simply cannot use switch. You should use a sequence of if-else commands, like this:
// store it in a variable so you do not call the method repeatedly
final int code = e.getKeyCode();
// this is instead of your switch
if (code == keys[KeyboardSettings.UP]) {
....
}
else if (code == keys[KeyboardSettings.DOWN]) {
...
}
else if (...) {
...
}
The deep reason for it is that you want to have the keys user-configurable, so you simply cannot know their values in compile-time.
You may study Runtime vs Compile time if you have not understood my last sentence.

Related

Is switch operator atomic?

In documentation it is said you could equally use if-else multiple times or switch-case:
int condition;
setCondition(int condition) {
this.condition = condition;
}
Either switch-case
switch (condition) {
case 1: print("one"); break;
case 2: print("two"); break;
or
if (condition == 1) { print("one"); }
else if (condition == 2) { print("two"); }
Next, conditionis declared volatile and method setCondition() is called from multiple threads.
If-else is not atomic and volatile variable write is a synchronizing action. So both "one" and "two" string could be printed in the last code.
It could be avoided if some method local variable with initial value was used:
int localCondition = condition;
if (local condition == ..) ..
Does switch-case operator hold some initial copy of variable? How are cross threads operations implemented with it?
From the Java specification on switch statements:
When the switch statement is executed, first the Expression is evaluated. [...]
This suggests that the expression is evaluated once and that the result is temporarily kept somewhere else, and so no race-conditions are possible.
I can't find a definite answer anywhere though.
A quick test shows this is indeed the case:
public class Main {
private static int i = 0;
public static void main(String[] args) {
switch(sideEffect()) {
case 0:
System.out.println("0");
break;
case 1:
System.out.println("1");
break;
default:
System.out.println("something else");
}
System.out.println(i); //this prints 1
}
private static int sideEffect() {
return i++;
}
}
And indeed, sideEffect() is only called once.
The expression is evaluated once when entering the switch.
The switch may use the result internally as many times as it needs to determine what code to jump to. It's akin to:
int switchValue = <some expression>;
if (switchValue == <some case>)
<do something>
else if (switchValue == <some other case>
<do something else>
// etc
Actually, a switch compiles to a variety of byte code styles depending on the number of cases and the type of the value.
The switch only needs to evaluate the expression once.

Storing variable changes during a switch [Java]

I am currently in the process of making a calculator for Android (I am not using any tutorials) and am running into an issue.
I have this:
public void buttonOnClick(View v){
int operation;
switch (v.getId()){
case R.id.one:
numberBox.append("1");
break;
case R.id.two:
numberBox.append("2");
break;
case R.id.plus:
operation=1;
break;
case R.id.eq:
if (operation == 1){
// Print value
}
break;
default:
break;
}
}
Note that this is not the exact code, it is just a mockup.
The problem is, with the scope of the case, when the operation is set to 1, it is not set publicly and when I go to read it in the equals case, it is set back to 0.
How can I fix this problem?
You must be new in Java or any other programming language:
local variables are only used in the method they are declared in.
Whenever you go out of the method the variable is destroyed as well as its value.
So each time you enter a new variable is initialized.
To make this work just create a global class variable and use it or
Pass an object to the method that holds some int variable : the current operation, then read/write the variable using that object.
In your case its better to use a global class variable:
public class MyClass {
int operation;
public int getOperation() {
return operation;
}
public void setOperation(int value) {
this.operation = value;
}
.....
THEN:
....
public void buttonOnClick(View v){
...
case R.id.plus:
this.operation = 1;
break;
case R.id.eq:
if (this.operation == 1){
// Print value
}
break;
.....

How to add ItemListeners dynamically?

I'm writing a program to calculate GPA. It consists of several panels. The first panel
tells the user to specify the number of courses so that Comboboxes (gradeCombo),(hourCombo) and Textfields will be added dynamically to the second panel . Everything is fine to this point but the problem is with the listeners. In early stages, I registered the event listeners for these comboboxes individually for every element in the array and it resulted in 900 lines of codes, but it worked fine and all my results were correct. To enhance my code I'm trying to write a for loop for registering the events for the comboboxes and so far I couldn't succeed.
I tried to write the handling code as anonymous inner class and as separate inner class, Here is my last try:
for(i = 0; i<courseN;i++)
{
hourCombo[i].addItemListener(new HoursHandler());
gradeCombo[i].addItemListener(new GradeHandler());
}
public class HoursHandler implements ItemListener
{
public void itemStateChanged(ItemEvent event)
{
if(event.getStateChange()==ItemEvent.SELECTED)
{
String hour;
hour = (String) hourCombo[i].getSelectedItem();
currentHour[i]=Integer.parseInt(hour);
aquiredHours=aquiredHours+currentHour[i] prevHour[i];
prevHour[i]=currentHour[i];
}
}
}
public class GradeHandler implements ItemListener
{
public void itemStateChanged(ItemEvent event)
{
if(event.getStateChange()==ItemEvent.SELECTED)
{
String grade;
grade=(String) gradeCombo[i].getSelectedItem();
switch(grade)
{
case "A+":
currentPoint[i]=5*currentHour[i];
break;
case "A":
currentPoint[i]= 4.75 * currentHour[i];
break;
case "B+":
currentPoint[i]= 4.5 * currentHour[i];
break;
case "B":
currentPoint[i]= 4 * currentHour[i];
break;
case "C+":
currentPoint[i]= 3.5 * currentHour[i];
break;
case "C":
currentPoint[i]= 3 * currentHour[i];
break;
case "D+":
currentPoint[i]= 2.5 * currentHour[i];
break;
case "D":
currentPoint[i]= 2 * currentHour[i];
break;
case "F":
currentPoint[i]= 1 * currentHour[i];
break;
}
aquiredPoints=aquiredPoints+currentPoint[i]-prevPoint[i];
prevPoint[i]=currentPoint[i];
}
}
}
I get a NullPointerException for this statement:
hour = (String) hourCombo[i].getSelectedItem();
and everything goes wrong, none of my variables is updated and I cannot calculate the GPA..
It's hard to tell from the posted code what is wrong there. However, I assume that i is declared as an instance variable. In this case, the loop for(i = 0; i<courseN;i++) will change the value of this instance variable. Afterwards, all the listeners will internally use i with the last value that it received in the for-loop.
To circumvent this, you can declare an instance variable for each listener instance. So you can change your listener classes like this:
public class HoursHandler implements ItemListener
{
private final int index;
HoursHandler(int index)
{
this.index = index;
}
#Override
public void itemStateChanged(ItemEvent event)
{
// Use the "index" here:
String hour = (String) hourCombo[index].getSelectedItem();
currentHour[index]=Integer.parseInt(hour);
...
}
}
(similarly, introduce such an index for the GradeHandler).
Then, when you create the listeners, you can pass to each instance the index that it refers to:
// Note: "i" is declared here, and should NO longer
// be an instance variable!
for(int i = 0; i<courseN;i++)
{
hourCombo[i].addItemListener(new HoursHandler(i)); // Use "i" as "index"
gradeCombo[i].addItemListener(new GradeHandler(i)); // Use "i" as "index"
}
I assume that there might be some more elegant solutions, but this is one possible solution, solely based on the code that you provided.
It appears that i is a member field in your outer class. When your listener is executed, and your listener
hour = (String) hourCombo[i].getSelectedItem();
this statement will use whatever value i happens to be in this outer class. And after you execute your for loop, i will probably be equal to courseN, unless there's something else changing it somewhere else. In any case, it doesn't use the value that i held when you set up the listener, because you did nothing to tell it to use that value.
A simple way to fix this is to construct your listeners by giving it the index you want them to use:
public class HoursHandler implements ItemListener
{
private final int index;
public HoursHandler(int index) {
this.index = index;
}
public void itemStateChanged(ItemEvent event)
{
if(event.getStateChange()==ItemEvent.SELECTED)
{
String hour;
hour = (String) hourCombo[index].getSelectedItem();
and use index instead of i everywhere in the listener. When you construct the listener, it will store the index you want, and then the code will use that instead of the current value of i. Similarly for GradeHandler. Then
for(i = 0; i<courseN;i++)
{
hourCombo[i].addItemListener(new HoursHandler(i));
gradeCombo[i].addItemListener(new GradeHandler(i));
}
Note that the index you want the listeners to use is now passed as a parameter to the listeners' constructors.
EDITED to use final on the index member--plagiarized from Marco13's good idea.

Regarding Switch conditional statement

I have the below piece of code that I have developed ..
public byte determineCardType(final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
if (isWagRewardsLoyaltyCard(inputData))
cardType = WAG_LOYALTY_CARD_TYPE;
else if (isDRCard(inputData)) //checking that card scanned and swiped is a DR Card
cardType = DR_CARD_TYPE;
else if (isWagRewardsPartnerCard(inputData))
cardType = AARP_CARD_TYPE;
return cardType;
} catch (Exception e) {
return UNKNOWN_CARD;
}
}
please advise me can the above code can be adjusted in switch loop, if yes then please advise, Thanks in advance.
the other code that is linked to it...
if((aarpCardSupport.isAARPCard(input))||(determineCardType(input)==DR_CARD_TYPE)) {
return true;
} else if((isDRCard(input))&&(isDRLoayltyEnabled())) { //would return 1 for DR card only when isDRLoayltyEnabled returns true
return true;
}
return false ;
Switch won't help you, but conditional expressions can:
return isWagRewardsLoyaltyCard(inputData) ? WAG_LOYALTY_CARD_TYPE
: isDRCard(inputData) ? DR_CARD_TYPE
: isWagRewardsPartnerCard(inputData) ? AARP_CARD_TYPE
: UNKNOWN_CARD;
I would strongly recommend against catching Exception, btw. Catch specific exception types if you must - although in that case I'd at least log the error before returning.
EDIT: As for the second piece of code, it looks like you just want:
return aarpCardSupport.isAARPCard(input)
|| determineCardType(input) == DR_CARD_TYPE
|| (isDRCard(input) && isDRLoayltyEnabled);
Although why determineCardType(input) would return something other than DR_CARD_TYPE when isDRCard(input) returns true is a mystery...
Don't do it. If you must do it, you could do it like this:
public byte determineCardType (final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
switch (isWagRewardsLoyaltyCard (inputData) ? 1 :
(isDRCard (inputData) ? 2 : (isWagRewardsPartnerCard (inputData) ? 3 : 4)))
{
case 1: cardType = WAG_LOYALTY_CARD_TYPE; break;
case 2: cardType = DR_CARD_TYPE; break;
case 3: cardType = AARP_CARD_TYPE; break;
default: // UNKNOWN_CARD already default
}
return cardType;
} catch (CardException ce) {
return UNKNOWN_CARD;
}
}
}
But since you return a cardType as byte, you can switch later, after setting the type. This code is harder to read than your code. Jons code is at least lean.
I see you're new to switch statements. So I elaborate a little.
A switch statement is useful if your input is in Integral form (int, byte, short, Enum), and if you can match it against a - mostly medium short list of values.
And if you otherwise would use a sequence of if/else statements. Case statements needn't be mutual exclusive, but most times they are.
In your case, you call 3 methods which return booleans, so the input isn't integral. But your output is.
Later in the code, you could write:
byte cardType = determineCardType (inputDate);
switch (cardType)
{
case WAG_LOYALTY_CARD_TYPE: doWlct (foo, bar); break;
case DR_CARD_TYPE: doDct (); break;
case AARP_CARD_TYPE: doAct (baz); foobar (); break;
case UNKNOWN_CARD: System.err.println ("Unknown card");
}
Else you would have to write:
if (cardType == WAG_LOYALTY_CARD_TYPE)
doWlct (foo, bar);
else if (cardType == DR_CARD_TYPE)
doDct ();
else if (cardType == AARP_CARD_TYPE) {
doAct (baz);
foobar ();
}
else ...
Since Java 1.7 switch over Strings is possible as well, but until then, you could only switch over integral types, and the case labels have to be literally constant and known at compile time.
In OOP, switch statements are often abandoned in favor of dynamic dispatch.
interface Card {
public abstract int authenticate ();
}
class WagLoyalityCard implements Card {
public int authenticate () {
doWlct (foo, bar);
}
}
class DrCard implements Card {
public int authenticate () {
doDct ();
}
}
// ... and so on
Card card = new DrCard ();
// authenticate:
card.authenticate ();
// depending on the card type, DrCard.authenticate () or
// WagCard.authenticate () gets called.

Use string in switch case in java

I need to change the following if's to a switch-case while checking for a String, to improve the cyclomatic complexity.
String value = some methodx;
if ("apple".equals(value)) {
method1;
}
if ("carrot".equals(value)) {
method2;
}
if ("mango".equals(value)) {
method3;
}
if ("orange".equals(value)) {
method4;
}
But I am not sure what value I'm going to get.
Java (before version 7) does not support String in switch/case. But you can achieve the desired result by using an enum.
private enum Fruit {
apple, carrot, mango, orange;
}
String value; // assume input
Fruit fruit = Fruit.valueOf(value); // surround with try/catch
switch(fruit) {
case apple:
method1;
break;
case carrot:
method2;
break;
// etc...
}
Everybody is using at least Java 7 now, right? Here is the answer to the original problem:
String myString = getFruitString();
switch (myString) {
case "apple":
method1();
break;
case "carrot":
method2();
break;
case "mango":
method3();
break;
case "orange":
method4();
break;
}
Notes
The case statements are equivalent to using String.equals.
As usual, String matching is case sensitive.
According to the docs, this is generally faster than using chained if-else statements (as in cHao's answer).
Learn to use else.
Since value will never be equal to two unequal strings at once, there are only 5 possible outcomes -- one for each value you care about, plus one for "none of the above". But because your code doesn't eliminate the tests that can't pass, it has 16 "possible" paths (2 ^ the number of tests), of which most will never be followed.
With else, the only paths that exist are the 5 that can actually happen.
String value = some methodx;
if ("apple".equals(value )) {
method1;
}
else if ("carrot".equals(value )) {
method2;
}
else if ("mango".equals(value )) {
method3;
}
else if ("orance".equals(value )) {
method4;
}
Or start using JDK 7, which includes the ability to use strings in a switch statement. Course, Java will just compile the switch into an if/else like construct anyway...
To reduce cyclomatic complexity use a map:
Map<String,Callable<Object>> map = new HashMap < > ( ) ;
map . put ( "apple" , new Callable<Object> () { public Object call ( method1 ( ) ; return null ; } ) ;
...
map . get ( x ) . call ( ) ;
or polymorphism
Just to make concrete emory's answer, the executable code is the following :
Map<String,Callable<USer>> map = new HashMap<String,Callable<User>>();
map.put( "test" , new Callable<User> () { public User call (){ return fillUser("test" ); }} ) ;
map.put( "admin" , new Callable<Utente> () { public Utente call (){ return fillUser("admin" ); }} ) ;
where user is a POJO, and then
User user = map.get(USERNAME).call();
finally the called method is somewhere :
private User fillUser(String x){
User user = new User();
// set something in User
return user;
}
Java does not support Switch-case with String. I guess this link can help you. :)
Here is a possible pre-1.7 way, which I can't recommend:
public class PoorSwitch
{
final static public int poorHash (String s) {
long l = 0L;
for (char c: s.toCharArray ()) {
l = 97*l + c;
}
return (int) l;
}
public static void main (String args[])
{
String param = "foo";
if (args.length == 1)
{
param = args[0];
}
// uncomment these lines, to evaluate your hash
// test ("foo");
// test ("bar");
switch (poorHash (param)) {
// this doesn't work, since you need a literal constant
// so we have to evaluate our hash beforehand:
// case poorHash ("foo"): {
case 970596: {
System.out.println ("Foo!");
break;
}
// case poorHash ("bar"): {
case 931605: {
System.out.println ("Bar!");
break;
}
default: {
System.out.println ("unknown\t" + param);
break;
}
}
}
public static void test (String s)
{
System.out.println ("Hash:\t " + s + " =\t" + poorHash (s));
}
}
Maybe you could work with such a trick in a generated code. Else I can't recommend it. Not so much that the possibility of a hash collision makes me worry, but if something is mixed up (cut and paste), it is hard to find the error. 931605 is not a good documentation.
Take it just as proof of concept, as curiosity.
We can apply Switch just on data type compatible int :short,Shor,byte,Byte,int,Integer,char,Character or enum type.
Evaluating String variables with a switch statement have been implemented in Java SE 7, and hence it only works in java 7. You can also have a look at how this new feature is implemented in JDK 7.
Java 8 supports string switchcase.
String type = "apple";
switch(type){
case "apple":
//statements
break;
default:
//statements
break; }
String name,lname;
name= JOptionPane.showInputDialog(null,"Enter your name");
lname= JOptionPane.showInputDialog(null,"Enter your father name");
if(name.equals("Ahmad")){
JOptionPane.showMessageDialog(null,"welcome "+name);
}
if(lname.equals("Khan"))
JOptionPane.showMessageDialog(null,"Name : "+name +"\nLast name :"+lname );
else {
JOptionPane.showMessageDialog(null,"try again " );
}
}}
Not very pretty but here is another way:
String runFct =
queryType.equals("eq") ? "method1":
queryType.equals("L_L")? "method2":
queryType.equals("L_R")? "method3":
queryType.equals("L_LR")? "method4":
"method5";
Method m = this.getClass().getMethod(runFct);
m.invoke(this);
String value = someMethod();
switch(0) {
default:
if ("apple".equals(value)) {
method1();
break;
}
if ("carrot".equals(value)) {
method2();
break;
}
if ("mango".equals(value)) {
method3();
break;
}
if ("orance".equals(value)) {
method4();
break;
}
}

Categories

Resources