I would like to use the switch command with choice defined in a resource file but I have the error:
error: constant expression required
Do you have any suggestion?
ressource file integers.xml
<integer name="readID">0x21</integer>
<integer name="readRevision">0x22</integer>
java file:
switch (cmd) {
case getResources().getInteger(R.integer.readID):
break;
case getResources().getInteger(R.integer.readRevision):
Log.d(TAG, "case revision");
break;
In Java the case part of a switch needs a constant value.
Java expects with getResources().getInteger(R.integer.readID) since it is a method call that the value may change at runtime.
See Java switch statement: Constant expression required, but it IS constant
for more information.
You may use an if, else if, else construct.
Just define your integers as static constants in a separate file (Constants.java perhaps).
Constants
public class Constants{
public static final int READ_ID = 0x11;
public static final int READ_REVISION = 0x22;
}
Switch
switch (cmd) {
case Constants.READ_ID:
break;
case Constants.READ_REVISION:
break;
}
Try
private int getInt(#IntegerRes int res){
return context.getResources().getInteger(res);
}
For example:
switch (cmd) {
case getInt(R.integer.readID):
break;
case getInt(R.integer.readRevision):
Log.d(TAG, "case revision");
break;}
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.
I know you can have something like
public enum letters{
A, B, C, D
}
then have something like with each letter having its own class with a method
switch(letters)
case A:
A.methodA();
break;
case B:
B.methodB();
break;
case C:
C.methodC();
break;
case D:
D.methodD();
break;
default:
System.out.println("Learn the alphabet");
but can you have something like
switch(listOfLetterEnums)
...
In my program I turn command line enum arguments into a list and I need to know how to run each of the enums' method from that list whether it be a switch statement or something else.
I should add when I try it I get an error saying "cannot convert List. Only convertible int values or enum variables" would converting to a list of enums work if the above is possib
You will need to put a for loop around the switch statement to parse each element of the list separately. If the list is an Iterable then it should look something like this:
for (letterEnum : listOfLetterEnums) {
switch(letterEnum) {
...
}
}
For this to work, your list will need to implement the Iterator interface or extend a class which implements it. In this case you probably want to extend ArrayList.
If the list is an array you can just parse each element of the array:
for (int i = 0; i < listOfLetterEnums.length; i++) {
switch(listOfLetterEnums[i]) {
...
}
}
public class Test {
private enum Foo {
ABC, DEF;
}
public static void main(String... args) {
List<Foo> myfoos = new ArrayList<Foo>();
myfoos.add(Foo.ABC);
for(Foo i:myfoos)
switch (i) {
case ABC:
System.out.println("do abc");
break;
case DEF:
System.out.println("do def");
break;
}
}
}
You need to loop over the list, and switch based on the value.
letters[] listOfLetterEnums = { letters.A, letters.B, letters.C, letters.D };
for(letter let : listOfLetterEnums)
{
switch(let)
{
case A:
A.methodA();
break;
case B:
B.methodB();
break;
case C:
C.methodC();
break;
case D:
D.methodD();
break;
default:
System.out.println("Learn the alphabet");
}
}
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;
}
}
I have this piece of code right here , I really don't get it why is that there is a "this" keyword in the switch statement, take a look at this code
public enum InstrumentType{
GUITAR,BANJO,MANDOLIN,DOBRO, FIDDLE ,BASS,
public String toString(){
switch(this){
case GUITAR:
return "Guitar";
case BANJO:
return "Banjo";
case DOBRO:
return "Dobro";
case FIDDLE:
return "Fiddle";
case BASS:
return "Bass";
case MANDOLIN:
return "Mandolin";
default:
return "Unspecified";
}
}
}
Here this refers to the current InstrumentType value
static void MyFunc( )
{
InstrumentType f = InstrumentType.GUITAR;
String s = f.toString();
}
When f.toString() is invoked. this will have GUITAR value
It refers to the current instance.
If you had an anum instance "foo":
String s = foo.toString();
this points to its container class/struct/enum like elements. in this case, this is used for InstrumentType. it's a basic rule for most of the OO languages.