Java Switch use variable in multiple cases best practice - java

I want to have a switch statement like the following:
switch (something)
{
case 1:
int a = 3;
...
break;
case 2:
int a = 4;
....
break;
}
This does not work because a can not be redefined in that scope. I see the following options:
just go with "a = 4" in case 2
put each case in braces
define the variable before the switch statement
use a different variable name in case 2
I don't really like any of those four. Which of those is the way to go, or am i missing the best solution?
I saw questions like this one, which suggest using braces, but they are not about the best way to do it, but about getting it to work at all.

I am guessing you are catching any exception with an illegalstateexception and using a default block.
default:
doSomething();
break;
The oracle style guide does not use braces. It also says that a falls through comment should be added wherever a statement has no break.
However, anything with more than one line can be wrapped in braces with no performance penalty, for readability and reliability. The braces tell the compiler to create a new scope and execute that code as a block. If all you do is change a, then it is not really necessary. If you can write your switch case statement on one line without braces, do it. Many things in java don't do braces in one line instances including if statements.
Next, you can redefine any variable you need to re-use or set in the statements outside of the switch statement. This would be the best practice to minimize continual instantiation of your integers.
If there is more then one line,you should try making a few methods then, go with:
int a=0;
switch (something)
{
case 1:{
a = 3;
...
break;
}
case 2:{
a = 4;
....
break;
}
default:
{
try{
throw new IllegalStateException();
}catch(IllegalStateException e)
{
e.printStackTrace();
}
}
}

The braces is the right way to do it. {} creates a new scope, which is exactly what you want.

You can also use Map:
Map<Integer, Integer> caseMap = new HashMap<Integer, Integer>() {{
put(1, 3);
put(2, 4);
}};
int a = caseMap.get(something);

Related

How to Call Multiple Methods in a Switch Case in Java

I'm learning how to build a table in Java with MVC and I am trying to have a switch case that both performs changes to the data in the model and also calls a method like this
public void update()
{ model.fireTableDataChanged(); }
to update the data presented on the table.
Here is the switch case
public Object getValueAt(int row, int col)
{ switch(col)
{ case 0: return row;
case 1: return car.on(car.stops());
default: return ""; }
}
Any assistance is greatly appreciated and if you need to see more of the code to help you answer my question I will provide it.
You seem to be under the incorrect understanding that cases end at the first semicolon. This is incorrect. Cases don't end until you end them with the close brace for the overall switch statement, or until you include a break. Between the case and the end of the case, you can have any number of lines of code that do (pretty much) anything you want.
Think of a switch almost like a function, where the only* way to exit the function is to reach a break statement, return statement, or the close brace at the end, in exactly the same way that you exit functions with return and reaching the end of the function.
switch(condition) {
case 1: fcnOne();
case 2: fcnTwoA(); fcnTwoB();
case 3: fcnThree; break;
default: fcnFour();
}
If the condition is 1 then fcnOne() is called. There is no break in fcnOne(), so the code continues on into case 2. This is often called falling through. fcnTwoA() is then called. The code continues to the next instruction, which is to call fcnTwoB(). The next instruction is fcnThree(). Finally, we encounter a break statement, which exits the switch block.
Yes, I am intentionally ignoring exceptions, System.exit(), and return values for non-void functions.
I've formatted your code differently. Hopefully, it makes it easier to understand the multiple statements. Try something like this:
public Object getValueAt(int row, int col) {
switch(col) {
case 0:
// You can add any number of statements here.
...
update();
return row;
case 1:
...
update();
return car.on(car.stops());
default:
...
update();
return "";
}
}

Java/C++: possible to have common code for multiple cases in switch?

I find myself running into this situation a lot and was wondering if there are way in Java or C++ or any other language for that matter that allows you to execute code that is common to multiple case statements in a switch but also specialize for individual cases aswell, e.g:
switch(var)
{
case Preceeding:
{
// code executed for both FollowingA and FollowingB
}
break;
case FollowingA:
{
// code executed for only FollowingA
}
break;
case FollowingB:
{
// code executed for only FollowingB
}
break;
}
instead of having to do this:
switch(var)
{
case FollowingA:
case FollowingB:
{
// code executed for FollowingA and FollowingB
switch(var)
{
case FollowingA:
{
// code executed for FollowingA
}
break;
case FollowingB:
{
// code executed for FollowingB
}
break;
}
}
break;
}
It really depends on what you are trying to do - not just from a "can you do this" perspective, but you also have to care for the fact that you or others will have to read and understand the code later.
I typically find that if there are some things that need to be done in more than one case of a switch, it should go into a function (most compilers will inline such code if it's small enough, so there is no performance loss).
So:
void CommonCode()
{
...
}
switch(var)
{
case A:
CommonCode();
...
break;
case B:
CommonCode();
...
break;
}
There are however quite a lot of different solutions to this problem, and it really should follow "what is the meaning of what your code does" that should guide how you solve this. Write code that is clear is the primary goal. If that doesn't work, design the code differently.
}

using an array for a switch case statement in java

I'm making a game, and i want the controls to be editable. well, i've got that part down, but they are being read and changed in a .txt file. that is the way i wanted it to work for now. the values are stored as the key value (ie. KeyEvent.VK_W is equal to 83, so the value for the line is 83). I also have it reading the values and saving them to a String array variable in my core class. In my key event class, the one that handles the pushing of the keys, i have it refering to the array to check if a command key was pushed. i'm continuously getting this error: case expressions must be constant expressions when i try it. here is the WRONG code:
switch(key){
case Integer.parseInt(commands[1]):
...
break;
}
and i get that error. the value of commands[1] is 83. it is the value for "W". here is my declaration of the variable:
for (int i = 0; i < commands.length; i++) {
commands[i] = io.readSpecificLine(FILES.controlsFileFinalDir,
i + 1);
}
and if i have it print out every value, it does work. i've tried making the array final but that didnt work. i've run across the solution before, about 2 years ago, but i cant find it again. does anyone have any ideas on how to fix this? thanks in advance!
As the compiler says, the case expressions must be constant expressions. You can't use an array element as a case expression. You can simply use an if/else if/else clause instead.
You can't use non-constant expressions in case statements. An alternative approach is to build a map from values to the actions. So instead of this (which doesn't actually make any sense to me):
switch (key) {
case Integer.parseInt(commands[1]):
// action 1
break;
// other cases...
default:
// default action
}
You can do something like this:
static Map<Integer, Runnable> keyMap = new HashMap<Integer, Runnable>();
static {
keyMap.put(83, new Runnable() {
#Override
public void run() {
// actions for code 83
}
});
. . .
}
(If it makes more sense, this could also be done on a per-instance basis instead of as a static map.) Then later:
Runnable action = keyMap.get(Integer.parseInt(commands[1]));
if (action != null) {
action.run();
} else {
// default action
}
If you need to pass variables to your actions, you can define your own interface instead of using Runnable for the actions.

Is it possible to replace if-else with switch statement using strings as switching values?

I'm wondering if it's possible to use switch statement instead of if-else one in this case. Variables are taken from JComboBoxes and processed by ActionEvent here:
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == comboUnit) {
String unit = comboUnit.getSelectedItem().toString();
if (unit.equals("Unit 1")) {
unitValue = Double.parseDouble(tfUnit.getText());
valMeter = unitValue * defined1;
labelDesc.setText("Unit 1");
convert();
}
else if (unit.equals("Unit 2")) {
unitValue = Double.parseDouble(tfUnit.getText());
valMeter = unitValue * defined2;
labelDesc.setText("Unit 2");
convert();
}
(...)
I was trying to pass pure strings as the values but with no success. Do you have any hints on how it should be done (and if it's even possible)?
Java 7 allows you to switch on Strings.
Your code needs refactoring though, and the question of whether to use switch or enumerations or maps, is something that comes second, I would say.
You have too much duplicated code doing essentially the same thing. I am referring to:
unitValue = Double.parseDouble(tfUnit.getText());
valMeter = unitValue * defined1;
labelDesc.setText("Unit 1");
convert();
Obviously, because you multiply using different factors depending on the unit used, you need a function of unit evaluating to the factor to use. In less mathematical terms, you need something that yields value of either defined1 or defined2 depending on a string supplied. You already have the unit referring to the "name" of your unit in question, you can use it. I call the method returning the factor for factor, taking in a unit name and returning a Number (since it does not follow from your example whether you are multiplying integers or real numbers of some sort). I am also assuming your defined1 and defined2 etc, are variables or literals.
unitValue = Double.parseDouble(tfUnit.getText());
valMeter = unitValue * factor(unit);
labelDesc.setText(unit);
convert();
Number factor(String unitName) {
switch(unitName) {
case "Unit 1": return defined1;
case "Unit 2": return defined2;
default: throw new Exception("Unknown unit");
}
}
The method itself is where your "to switch or not to switch" problem creeps in. You are free to use a map if you want:
Map<String, Number> unitNameValueMap = new HashMap<String, Number>();
unitNameValueMap.put("Unit 1", defined1);
unitNameValueMap.put("Unit 2", defined2);
Number factor(String unitName) {
Number result = unitNameValueMap.get(unitName);
if(result == null) throw new Exception("Unknown unit");
return result;
}
Or you can use enumerations:
enum UnitValue {
UNIT1(defined1), UNIT2(defined2);
final Number value;
private UnitValue(Number value) {
this.value = value;
}
}
Number factor(String unitName) {
return Enum.valueOf(UnitValue.class, "UNIT" + Integer.parseInt(unitName.substring(5)).value;
}
You can even switch or use a map inside enumerations, which will give you good code readability as well.
You need to profile your program to see if you need switch-based solution or enum-based one or a map-based one. The way it currently stands and as you can see for yourself, the enum-based solution is a bit messy because of relationship between your unit names, enumeration constants, and their values. If someone can do better with enums, then take their code instead, naturally.
Usually, shortest code is best, as it is easier to read and most often understand. But be careful with maps - they induce more overhead than other solutions, so I for one prefer to use them where I have fewer maps with many keys each, not the other way around.
You mean like
switch (unit) {
case "Unit 1":
// do something
break;
case "Unit 2":
}
?
Yes you can, starting with Java7.
But in your case, you don't seem to need neither switch nor if/else. You do the same thing in both cases :
String unit = comboUnit.getSelectedItem().toString();
unitValue = Double.parseDouble(tfUnit.getText());
valMeter = unitValue * defined1;
labelDesc.setText(unit);
convert();
You can use Enum and replace string with Enum values
public static void main(String[] args) {
Units unit = Units.Unit1;
switch (unit) {
case Unit1:
break;
case Unit2:
break;
}
}
enum Units {
Unit1, Unit2,
}
Java 7 allows you Using Strings in switch Statements
Only in Java 7 and later is it possible to use Strings in a switch-case statement. Here is a link to the documentation, you will need to scroll down to the String section.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

Weird compilation error when using switch on enumeration

I just noticed one curious case and wanted to see if someone will be able to explain it. Here is my case:
private enum Classifiers {
NEURAL_NETWORK, NEAREST_NEIGHBOURS, IDENTITY;
}
private ClassifierInterface getClassifierInstance(Classifiers classifier) {
switch (classifier) {
case NEURAL_NETWORK:
return new DoubleLayeredNeuralNetwork();
case NEAREST_NEIGHBOURS:
return new NearestNeighbours();
case IDENTITY:
return new IdentityClassifier();
}
return null; // If I comment out this line I get compilation error
}
See the comment. I would expect that Unreachable code error will be reported for this line. Instead I get Method must return value error if I comment out this line. However, there is no way the program flow will pass through there.
I even assumed it would be a guard case for the case of null value passed-in, but as expected this triggers NullPointerException for the switch condition.
I do not use switch very often, probably I am missing something here. Can somebody please try to help understand this behaviour?
That is correct behaviour as you do not have a default case statement. The problem is that you could add an value to the enum later and not re-compile the code which uses it. By forcing you to always handle when it is not one of the values, this is covered.
BTW: classifier could be null which is another option switch doesn't handle unfortunately.
That question is interesting...
We have something like this and the compiler is happy!
public enum Coin {
PENNY,
NICKEL,
DIME,
QUARTER;
}
private enum CoinColor { COPPER, NICKEL, SILVER }
private static CoinColor color(Coin c) {
switch(c) {
case PENNY:
return CoinColor.COPPER;
case NICKEL:
return CoinColor.NICKEL;
case DIME: case QUARTER:
return CoinColor.SILVER;
default:
throw new AssertionError("Unknown coin: " + c);
}
}
The Java Languaje Specification says:
A Java compiler is encouraged (but not required) to provide a warning
if a switch on an enum-valued expression lacks a default label and
lacks case labels for one or more of the enum type's constants. (Such
a statement will silently do nothing if the expression evaluates to
one of the missing constants.)

Categories