Switch statements with identical control expressions but different case implementations - java

I have two switch statements that are identical in structure but the cases do different things. How do I possibly combine them? Or are there any better design suggestions instead of using two switch statements?
This is how the first switch statement looks:
switch(var){
case 1:
functionA();
break;
case 2:
functionB();
break;
}
The second looks like this:
switch(var){
case 1:
functionC();
break;
case 2:
functionD();
break;
}
Problem is, functionA() cannot be called at the same time with functionC() and same goes for functionB() and functionD() - they are to be called at different times.
Forgive me if this sounds silly, but is there a way to re-use one switch statement for different situations?
NB: This is not a "how do I do this?" question, but a "how do I do this BETTER question".

In my optionion there is no need to further simplify your switch statements, since they are readable and do different things. Also, in order to simplify you would need to add an additional layer of abstraction, which is not (really) possible here.
The only thing you could abstract here is the var parameter. Altough i would not recommend it, maybe you can try something like this:
private Consumer<Integer> createConsumer(Runnable... actions) {
return i -> {
if (actions.length < i)
throw new IllegalArgumentException();
actions[i].run();
};
}
You can create a consumer, which accepts an arbitary amount of Runnable objects
var consumer = createConsumer(
() -> System.out.println("First"),
() -> System.out.println("Second"),
() -> System.out.println("Third"));
and execute it like
consumer.accept(0);
If you also need a default statement Consumer<Integer> createConsumer(Runnable... actions, Runnable defaultOption) could come to rescue, then the IllegalArgumentException would also be superfluous.
However, this would just be some functional style of switch statement, which could make things even more complicated, whenever the parameter does not start at 0, but some other number (you would need to subtract till 0) or if you switch block has "gaps" bewteen numbers (0, 1, 3, ...).

Related

Philosophy of variable's scope in a switch statement

As answered in this question here, the scope of a variable inside of a case belongs to the entire switch statement itself, not just the case. Therefore, this does not compile (duplicate local variable):
int key = 2;
switch (key) {
case 1:
String str = "1";
return str;
case 2:
String str = "2";
return str;
}
I'm interested in mainly two things...
What's the philosophy, or design principle, behind this behavior? (Maybe I'm even asking for the motivation for the switch statement as a whole?)
How does this happen? How does this code look at the bytecode, or even assembly, level?
For better or worse, the semantics of switch in Java were heavily influenced by the semantics of switch in C. And, while we as programmers tend to think of a case label followed by some statements and a break/continue/return as a logical unit, that's not actually how it works, and no such construct exists at the language level. In a switch, break and continue are just statements, and when you execute a switch, you start at the matching case label and execute the remainder of the block. It just so happens that most of the time, you'll hit a break or continue or return before that happens. (See JLS 14.11.) The key sentence is:
All statements after the matching case label in the switch block, if any, are executed in sequence.
Many people believe (IMO, reasonably so) that the switch statement in Java has its priorities backwards; the language treats fallthrough and other control flow oddities as if they were normal case, and break as the exceptional case. But of course, in real code, it's the other way around. (How did Java acquire these backward priorities? By copying from C.)
The scoping rule for switch statements flows pretty directly from this view of the world; if the body of a switch is an undifferentiated block that happens to be peppered with case labels, of course its one big scope. Never mind that this is not actually what almost all developers want almost all the time.
In addition to confusing scoping and fallthrough-by-default, Among the other things people regret about switch in Java is that it is only a statement, not an expression. See JEP 325, which addresses all of these problems (in a backward-compatible way), which will likely be a preview features in Java 12.
Just put a pair of braces around each case clause:
int key = 2;
switch (key) {
case 1: {
String str = "1";
return str;
} case 2: {
String str = "2";
return str;
}
}
This will compile.

Switch Case statement enum not working?

I have a problem concerning switch/case statements in java in combination with enums.
In my code I want to do something based on the Enum of the type "MatchingMethods" set in the object "currentMethod".
The enum "MatchingMethods" contains several enums in the form
{EXACT_STRING_MATCHING, DEPTH_MATCHING, [...]}
Now the strange thing is though the object "currentMethod" contains an enum of the type "EXACT_STRING_MATCHING" not only the first case is executed but also the second one.
I know there is no break statement after the code of the first case but the code of the second case shouldn't be executed in my opinion because the enum "EXACT_STRING_MATCHING" doesn'T match with "DEPTH_MATCHING".
If I put in a break statement after the first case it seem to be totally fine…
My code is the following:
[...]
MatchingMethods mM = currentMethod.getMatchMethod();
switch (currentMethod.getMatchMethod()) {
case EXACT_STRING_MATCHING:
//do something here
case DEPTH_MATCHING:
comparedNodePair.setDepthMatchResult(currentMetricResult);
break;
[...]
I am totally confused…
May someone be able to help me?
You already mentioned it, you have no break - switch works like goto where the case are labels to be jumped at and no "boundaries" or functions.
This is also the biggest critique concerning switch, because no one would use goto today, but switch which is certainly similar.
But it gets executed, because once one of the case satements is true the flow of execution "falls trough" see here for some information
this is normal if there is no break statement at the end of the case block.
add the break statement is necessary if you only want the exact block to be executed.

How to achieve a switch case block which is scalable?

While starting to build an application, I stared using a switch case block with only five cases to be considered. Later when the build progressed, more cases came into picture and that started creating problems. I know I might have designed it wrongly at the first place, but if such things come as a change how do I effectively approach this? An example is given below
Starting with this
switch case 1: /*do function1()*/ break;
case 2: /*do function2()*/ break;
Later, a 100 cases come in
switch case 1: /*do function1()*/ break;
case 2: /*do function2()*/ break;
....
case 100: /*do function100()*/ break;
I am sure that converting these cases into 100 if conditions is not going to be a very good approach, so is there a way this can be done?
Please consider that the functions given in the code above are simple mathematical functions for now.
Consider an interface like this:
public interface MyFunction {
public void compute();
}
and a Map with the previous interface as values:
Map<Integer,MyFunction> myFunctionsMap = new HashMap<>();
You need to initialize the map with all of you functions:
myFunctionsMap.put(1,new MyFuntion() {
#Override
public void compute() {
/*do function1()*/
}
});
for each of your functions, the syntax might be a bit heavy with anonymous classes, you can implement you functions in separate classes and use them as well.
Now instead of the switch, you simply use the map:
myFunctionsMap.get(theValueSwitched).execute();
Depending of how you initialize the map, the values of the keys and how you use it, you might want to check myFunctionsMap.contains(theValueSwitched) (this would be your default case if you have one).
Edit: Java 8 shorter syntax would be myFunctionsMap.put(1,() -> {/*do function1()*/});
You could name your methods something like method1, method2, method3 , etc .. and use reflexion to call them, using you variable. You wouldn't have a lengthy switch, that way.
I have no ideas if that is efficient or not, though.
Here's a neat exemple, from wikipedia's reflection page.
Object foo = Class.forName("complete.classpath.and.Foo").newInstance();
// Alternatively: Object foo = Foo.class.newInstance();
Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
m.invoke(foo);
hope that helps

Is it possible to use an Integer to call methods and arrays dynamically?

For example:
3 methods exist
"map1method,
map2method,
map3mehtod"
and I want to call the right one depending on what the integer 'activemap' has currently stored in it.
I could do an If statement
"If (activemap == 1)
map1method;
elseif (activemap ==2)
..."
But is there a possible way of using the integer more efficiently?
Like a "map(activemap)method"
Also could I also call a specific array in a batch of them in the same fashion.
This is all in java by the way.
It is possible via reflection but I would urge you to stay away from that approach. Why not have all three methods built into one? One option would be to use a switch statement to handle the various cases:
void mapMethod(int activemap) {
switch (activemap) {
case 1:
// map1method
break;
case 2:
// map2method
break;
case 3:
// map3method
break;
default:
break;
}
}
Now, you can call
mapMethod(activemap)
If you want to take the reflection approach instead (which as I said I don't think you should), you can do something along the lines of
String methodName = "map" + activemap + "method";
MyClass.class.getDeclaredMethod(methodName).invoke(null);
A switch statement would be slightly easier to read:
switch(activemap) {
case 1: map1method(); break;
case 2: map2method(); break;
}
You could use reflection to build the method name up at runtime, but that wouldn't be simpler. Reflection is a lot of code.
The most effective way to do this is to either create an enum to represent the different calls and use the int as a lookup for the enum value, or if that's not possible, to use a switch statement. You can use reflection to accomplish what you're talking about (look up a method at runtime based on its name), but it's less efficient and more cumbersome than either of those options.
You can do it using Reflection, It will be something like this:
java.lang.reflect.Method method;
method = myObject.getClass().getMethod("map+"activemap"+method", param1.class, param2.class, ..);
method.invoke(object, arg1, arg2,...);

Java style: Variable declaration in a switch

The following code does not compile because eater is defined twice:
switch (vegetable) {
case TOMATO:
Eater eater = new Eater(Tomato.class, many parameters);
eater.eat(more parameters);
return true;
case POTATO:
Eater eater = new Eater(Potato.class, many parameters);
eater.eat(more parameters);
return true;
case CARROT:
doSomethingElse();
return true;
}
Should I:
Use separate variables `tomatoEater` and `potatoEater`, making the code less maintainable?
Define `eater` before the `switch`, making it accessible to more than it should?
Define `eater` the first time only, leading to potential confusion?
Add braces, making the code more verbose?
Any better idea?
I would personally either use braces, or just abandon the local variable completely:
new Eater(Potato.class, many parameters)
.eat(more parameters);
The disadvantage of this is that it makes it a little harder to debug. Obviously this isn't your real code though... which makes it hard to say the right thing to do. It's quite possible that the right thing to do is actually to break out the bodies of the cases into separate methods.
Why not this:
switch (vegetable)
{
case TOMATO:
new Eater(Tomato.class, many parameters).eat(more parameters);
return true;
case POTATO:
new Eater(Potato.class, many parameters).eat(more parameters);
return true;
case CARROT:
doSomethingElse();
return true;
}
If you dont have any use of the Eater reference anywhere else later, I would do this.
Not quite the same logic as your method (carrot is treated as default) but shows an alternative approach (with some more behind the scenes wiring that I haven't worried about here):
Eater eater = vegetable.getEater(many parameters);
if (eater != null) eater.eat(more parameters);
else doSomethingElse();
return true;
How would using separate variables make the code less maintainable? (first bullet point). If anything I would say it would do the opposite as the variable name better explains what it is. I would go with that if keeping it in that scope is important to you.
Maybe using a switch isn't such a good idea at all.
In what better example can represent a switch statement in Java ?

Categories

Resources