Is there any alternative way to implement a switch case in Java other than if else which is not looking good. A set of values will be there in combination, according to the selection corresponding method has to be executed.
-
What do you mean when you say 'A set of values will be there in combo' ? – Alterlife Sep 15 '09 at 07:35
-
Already asked similar question http://stackoverflow.com/questions/126409/ways-to-eliminate-switch-in-code – Biju CD Sep 15 '09 at 07:42
-
@cdb: So WHY did you ask it again? What didn't the previous answers tell you? – Stephen C Sep 15 '09 at 11:01
14 Answers
If you have plenty of switch/case statements around your code and they are driving you crazy.
You could opt for the Refactoring: Replace conditional with polymorphism.
Let's say you have a piece of software that is used to save information to different devices: 4 persistence operations are defined: fetch, save, delete, update, which could be implemented by N number of persistence mechanism ( flat files, network, RDBMS, XML, etc ) .
Your code have to support them all so in 4 different places you have this:
BEFORE
class YourProblematicClass {
....
public void fetchData( Object criteria ) {
switch ( this.persitanceType ) {
case FilePersistance:
// open file
// read it
// find the criteria
// build the data
// close it.
break;
case NetWorkPersistance:
// Connect to the server
// Authenticate
// retrieve the data
// build the data
// close connection
break;
case DataBasePersistace:
// Get a jdbc connection
// create the query
// execute the query
// fetch and build data
// close connection
break;
}
return data;
}
Same for save/delete/update
public void saveData( Object data) {
switch ( this.persitanceType ) {
case FilePersistance:
// open file, go to EOF, write etc.
break;
case NetWorkPersistance:
// Connect to the server
// Authenticate
// etc
break;
case DataBasePersistace:
// Get a jdbc connection, query, execute...
break;
}
}
And so on....
public void deleteData( Object data) {
switch ( this.persitanceType ) {
case FilePersistance:
break;
case NetWorkPersistance:
break;
case DataBasePersistace:
break;
}
}
public void updateData( Object data) {
switch ( this.persitanceType ) {
case FilePersistance:
break;
case NetWorkPersistance:
break;
case DataBasePersistace:
break;
}
}
Using switch/case statement becomes problematic:
Each time you want to add a new type you have to insert new switch/case in each section.
Many times, some types are similar, and they don't need a different switch/case ( you could cascade them )
Some other they are, and some times they differ slightly
You may even need to load different type at runtime ( like plugins )
So the refactoring here would be to add an interface or abstract type and have the different types implement that interface and delegate the responsibility to that object.
So you would have something like this:
AFTER
public interface PersistenceManager {
public void fetchData( Object criteria );
public void saveData( Object toSave );
public void deleteData( Object toDelete );
public void updateData( Object toUpdate );
}
And different implementations
public class FilePersistence implements PersistanceManager {
public void fetchData( Object criteria ) {
// open file
// read it
// find the criteria
// build the data
// close it.
}
public void saveData( Object toSave ) {
// open file, go to EOF etc.
}
public void deleteData( Object toDelete ){
....
}
public void updateData( Object toUpdate ){
....
}
}
And the other types would implement according to their logic. Network would deal with sockets, and streams, DB would deal with JDBC, ResultSets etc. XML with node etc.etc.
public class NetworkPersistence implements PersistanceManager {
public void fetchData( Object criteria ) {
// Socket stuff
}
public void saveData( Object toSave ) {
// Socket stuff
}
public void deleteData( Object toDelete ){
// Socket stuff
}
public void updateData( Object toUpdate ){
// Socket stuff
}
}
public class DataBasePersistence implements PersistanceManager {
public void fetchData( Object criteria ) {
// JDBC stuff
}
public void saveData( Object toSave ) {
// JDBC stuff
}
public void deleteData( Object toDelete ){
// JDBC stuff
}
public void updateData( Object toUpdate ){
// JDBC stuff
}
}
And finally you just have to delegate the invocations.
Later:
public YouProblematicClass { // not longer that problematic
PersistamceManager persistance = // initialize with the right one.
public void fetchData( Object criteria ) {
// remove the switch and replace it with:
this.persistance.fetchData( criteria );
}
public void saveData( Object toSave ) {
// switch removed
this.persistance.saveData( toSave );
}
public void deleteData( Object toDelete ){
this.persistance.deleteData( toDelete );
}
public void updateData( Object toUpdate ){
this.persistance.updateData( toUpdate );
}
}
So, you just have to create the correct instance for the persistence manager according to the type only once. Then all the invocations are resolved by polymorphism. That's one of the key features of Object Oriented Technology.
If you decide you need another persistence manager, you just create the new implementation and assigned to the class.
public WavePersistance implements PersistanceManager {
public void fetchData( Object criteria ) {
// ....
}
public void saveData( Object toSave ) {
// ....
}
public void deleteData( Object toDelete ){
// ....
}
public void updateData( Object toUpdate ){
// ....
}
}
Presumably you're struggling with the requirement of case's being constant. Typically this is a code-smell, but there are things you can do. You might want to raise and link to another question that details why you're trying to switch.
Map<String,Object> map = new HasMap<String,Object>();
// ... insert stuff into map
// eg: map.add("something", new MyObject());
String key = "something";
if (map.contains(key)) {
Object o = map.get(key);
}
In the example above, you might want to map to 'handlers', something like
interface Handler {
public void doSomething();
}
which then makes this all turn into a lookup.
if (map.contains(key)) { map.get(key).doSomething(); }
Again, it's a bit of a smell, so please post a question which illustrates the reasoning.

- 11,730
- 4
- 40
- 68
-
3
-
-
1Why do the contains and then get, your reading from the map twice. Command comment = map.get( key ); if( null != command ){ ...command.execute(); } – mP. Sep 15 '09 at 08:11
-
Depending on implementation, the contains may not be too expensive. Knowing if there's an entry also allows you to handle a 'default' action in a sensibly readable manner. Premature optimization and all that. This actually is probably a hangover from my doing this often enough in Perl to avoid autovivification... – ptomli Sep 15 '09 at 08:19
-
To take the Enums a step farther, you can set up each enum constant with a handling method, making it value.doSomthing(). – deterb Sep 15 '09 at 22:13
Refactoring your code to use polymorphism could get rid of the need for a switch statement. However, there are some legitimate uses for switch so it depends on your situation.

- 51,004
- 28
- 112
- 141
-
3Yes- this is a well known refactoring- http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html – RichardOD Sep 15 '09 at 07:43
-
Nice link. Looks like there are a lot of good ones in the catalog. – Taylor Leese Sep 15 '09 at 07:49
For an alternate to switch statement, I think the best solution will be using an enum. For example: Consider the case below:-
public enum EnumExample {
OPTION1{
public double execute() {
Log.info(CLASS_NAME, "execute", "The is the first option.");
return void;
}
},
OPTION2{
public double execute() {
Log.info(CLASS_NAME, "execute", "The is the second option.");
return void;
}
},
OPTION3{
public double execute() {
Log.info(CLASS_NAME, "execute", "The is the third option.");
return void;
};
public static final String CLASS_NAME = Indicator.class.getName();
public abstract void execute();
}
The above enum can be used in the following fashion:
EnumExample.OPTION1.execute();
Hopefully this helps you guys.

- 23
- 3
or one could imagine a kind of dynamic switch case:
public interface Task<T>
{
public void doSomething(T context);
}
public Class SwitchCase<T>
{
Map<Integer,Task<T>> tasks;
Task<T> defaultTask;
public void choose(int choice, T context)
{
Task<T> t= this.tasks.get(choice);
if(t!=null) { t.doSomething(context); return;}
if(defaultTask!=null) { defaultTask.doSomething(context);}
}
}

- 34,472
- 31
- 113
- 192
I guess "Clean Code" has a nice chapter according switch/case vs. if/else.
Besides: I think it makes sense to decide whether you can reduce "noise" and make the code cleaner by using switch case, polymorphism or even a good ol' if/else. The number of cases plays a major role here, I guess.
I post a typical case how I replaced switch case with enum.
before refactor I have enum PatternTypes
:
public enum PatternTypes {
ALPHA_CHAR, ALPHANUMERIC_CHAR, ADDITIONAL_CHAR, UNICODE_BMP_CHARS
}
and function:
private static final String ALPHA_CHAR = "[a-zA-Z]+";
private static final String ALPHANUMERIC_CHAR = "[a-zA-Z0-9\\_]+";
private static final String ADDITIONAL_CHAR = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+";
private static final String UNICODE_BMP_CHARS = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+";
/*
* Match given classAbbr with given RegEx pattern
*/
private void checkInvalidClassAbbr(String classAbbr,
PatternTypes classAbbrPattern) {
switch (classAbbrPattern) {
case ALPHA_CHAR:
checkUnmatched(classAbbr, ALPHA_CHAR, CLASS_ABBR_VAR_NAME);
break;
case ALPHANUMERIC_CHAR:
checkUnmatched(classAbbr, ALPHANUMERIC_CHAR, CLASS_ABBR_VAR_NAME);
break;
case ADDITIONAL_CHAR:
throw new MalFormedDNException("Not support Pattern Type:"
+ classAbbrPattern);
case UNICODE_BMP_CHARS:
throw new MalFormedDNException("Not support Pattern Type:"
+ classAbbrPattern);
}
}
After refactor PatternTypes
modified to:
public enum PatternTypes {
/**
* RegEx patterns divided by restriction level
*/
ALPHA_CHAR("[a-zA-Z]+"),
ALPHANUMERIC_CHAR("[a-zA-Z0-9\\_]+"),
ADDITIONAL_CHAR("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"),
UNICODE_BMP_CHARS("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+");
public String getPatternContent() {
return patternContent;
}
private String patternContent;
PatternTypes(String patternContent) {
this.patternContent = patternContent;
}
}
and function simplify to:
/*
* Match given classAbbr with given RegEx pattern
*/
private void checkInvalidClassAbbr(String classAbbr, PatternTypes classAbbrPattern) {
if (PatternTypes.ADDITIONAL_CHAR.equals(classAbbrPattern) || PatternTypes.UNICODE_BMP_CHARS.equals(classAbbrPattern)){
throw new MalFormedDNException("RegEx pattern:" + classAbbrPattern.name() + "is not allowed for Class Abbr");
}
checkUnmatched(classAbbr, classAbbrPattern.getPatternContent(), CLASS_ABBR_VAR_NAME);
}

- 2,031
- 3
- 22
- 28
-
I like it but doesn't that just replace the select with a load of IF? And isn't IF the new code smell? – DannyK Jul 16 '20 at 13:32
Hashmap is considered not to be memory friendly, so you can use Enum for this purpose.
Example:
class EnumExample4{
enum Season{
WINTER(5), SPRING(10), SUMMER(15), FALL(20);
private int value;
private Season(int value){
this.value=value;
}
}
public static void main(String args[]){
System.out.println(Season.WINTER.value); //This gives you 5
}}
This will sve you from writing Switch Case or if statements.

- 59
- 1
-
3Can you give some reference to support the claim *Hashmap is considered not to be memory friendly*? If you can, please edit your answer to link it there. – derM - not here for BOT dreams May 10 '17 at 11:12
What do you want to do? Why is not Switch-Case good enough?
The fast answer is: use if-else

- 4,438
- 1
- 23
- 26
if () {}
else if () {}
...
else if () {}
?
But I wouldn't say it is better...
How about an if
(along with else if
and else
) statement? While switch
will only allow you to switch using equality against integer or Enum types, if
lets you use any boolean logic.

- 51,711
- 9
- 123
- 115
You could always replace a switch with if-else if-else if-else if...
, though I don't see why you'd want to. Depending on the context switch
s can also sometimes be replaced by arrays or hashmaps.

- 363,768
- 54
- 674
- 675