Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I replace a switch in Java with a list that references a variable for each case?

I was unable to find a prior question like this here (which surprises me), so..

I have a working Java program where part of it analyzes typed input. Some input 'options' are the strings in the cases below.

switch (varName.toLowerCase())  {
    case "steps":
        common.steps = true;
        break;
    case "scale":
        common.scale = true;
        break;
    case "float":
        common.fracts = false;
        break;
    case "fraction":
        common.fracts = true;
        break;
    case "spaces":
        common.spaces = false;
        break;
    ... etc.
}

In C or C++, I could shorten this code by making a list (which is a structure containing a string name and a variable pointer) such as

LIST varAction[] = { { "steps", &common.steps },
                     { "scale", &common.scale },
                     .. etc.
                   };

and then simply checking in a loop with i = 0 thru size of the list

if ( strcmp(varAction[i].name, input) == 0)  {
    *varAction[i].pointer = condition;
}

The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.

I could use a hashed index into an array using the hash of the string, but that would prevent me from using the specific variable names thru the code as needed, making that code less clear... i.e. I don't want to do (pseudo-code)

hashTable[varName] instead of (for example)  

if ( common.fracts )
     { do something }

There must be a better way? Is there? Thanks in advance.

like image 954
MultilingualProgrammer Avatar asked Sep 04 '16 13:09

MultilingualProgrammer


People also ask

What can be used instead of switch case in Java?

conditional statements - Alternative to Switch Case in Java - Stack Overflow.

How do you use multiple cases on a switch?

The switch can includes multiple cases where each case represents a particular value. Code under particular case will be executed when case value is equal to the return value of switch expression. If none of the cases match with switch expression value then the default case will be executed.

Can variables be used in switch case?

You can't because the language doesn't work that way.


4 Answers

From your question, it's fairly clear that you know you can't do what you've said you'd do in C/C++, but just for others coming to the question: Java doesn't have references to variables.

It's tempting to push the question out a level: Look at why you have varName in the first place and see if you can avoid it.

The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.

That suggests that common should have accessor function(s) for this information, so the switch exists only in one place (the getter) or two places (the getter and the setter).

void setThingy(String name, boolean value) {
    switch (name.toLowerCase())  {
        case "steps":
            this.steps = value;
            break;
        case "scale":
            this.scale = value;
            break;
        case "float":
            this.fracts = value;
            break;
        case "fraction":
            this.fracts = value;
            break;
        case "spaces":
            this.spaces = value;
            break;
        // ... etc.
    }
}

boolean getThingy(String name) {
    switch (name.toLowerCase())  {
        case "steps":
            return common.steps;
        case "scale":
            return common.scale;
        case "float":
            return this.fracts;
        case "fraction":
            return this.fracts;
        case "spaces":
            return this.spaces;
        // ... etc.
    }
}

If common's class isn't something you can change, a static utility function somewhere would also work, but better if it's in the class if possible.

like image 197
T.J. Crowder Avatar answered Sep 21 '22 22:09

T.J. Crowder


With Java 8+ you could use something like:

Map<String, Runnable> actions = new HashMap<> ();
actions.put("steps", () -> common.steps = true);
actions.put("scale", () -> common.scales = true);
//etc.

then in your code:

actions.get(varName.toLowerCase()).run(); //need null check

You could do it with Java 7- too using anonymous classes but it would be more verbose.

like image 32
assylias Avatar answered Sep 20 '22 22:09

assylias


Here’s an option, developing my idea from the comment just a little bit. Not sure whether you will like it, I’d like to offer it in case.

public class Common {

    private Map<String, Boolean> options = new HashMap<>();

    public void setOption(String varName, boolean condition) {
        options.put(varName.toLowerCase(), condition);
    }

    public boolean isSteps() { return options.get("steps"); }
    public boolean isFracts() { return options.get("fractions"); }
    public boolean isScale() { return options.get("scale"); }

}

You may want to put in some defense, for instance to avoid setting non-existing options.

Edit: Drawing on David Foerster’s comments on enums, here’s a solution using them:

public enum Option {

    steps, scale, fraction;

    private boolean option = false;

    public static void setOption(String varName, boolean condition) {
        valueOf(varName.toLowerCase()).option = condition;
    }

    public boolean isSet() {
        return option;
    }

}

Now the lookup happens in the setter, not in the getter. Defence against setting non-existing options is built-in: you will get an exception if you try, this behaviour can of course be modified if you prefer. The solution is quite extensible, it’s easy to add more enum constants if the need arises.

like image 32
Ole V.V. Avatar answered Sep 18 '22 22:09

Ole V.V.


Warning: It's been a while since I last wrote some Java, and this is probably against best practices, so continue with care! Also it's just a quick and dirty example, I wrote this on a (not up to date) mobile phone...

You could try to use reflection:

class Common {
  public boolean a;
  public boolean b;
  public boolean tryToSet(String field, boolean value) throws java.lang.Exception {
    Class<?> cl = this.getClass();
    try {
      Field f = cl.getDeclaredField(field);
      f.setBoolean(this, value);
      return true;
    } catch(NoSuchFieldException e) {
      return false;
    }
  }
}

Returning a boolean gives you the possibility to implement a "default case":

if (! c.tryToSet("x", false)) {
  System.out.println("some default case");
}
like image 37
Daniel Jour Avatar answered Sep 20 '22 22:09

Daniel Jour