Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to Switch Case in Java

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.

like image 536
Biju CD Avatar asked Sep 15 '09 07:09

Biju CD


People also ask

What can be used instead of switch case?

Luckily, JavaScript's object literals are a pretty good alternative for most switch statement use-cases I can think of. The idea is to define an object with a key for each case you would have in a switch statement. Then you can access its value directly using the expression you would pass to the switch statement.

Can we use if-else instead of switch case?

If there are only few cases, it might not effect the speed in any case. Prefer switch if the number of cases are more than 5 otherwise, you may use if-else too. If a switch contains more than five items, it's implemented using a lookup table or a hash list.

Which of the following is the alternative of the switch statement?

Some alternatives to switch statements can be: A series of if-else conditionals that examine the target one value at a time. Fallthrough behavior can be achieved with a sequence of if conditionals each without the else clause.


4 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 ){
           //  ....
        }
   }
like image 70
OscarRyz Avatar answered Oct 01 '22 17:10

OscarRyz


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.

like image 29
ptomli Avatar answered Oct 01 '22 16:10

ptomli


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.

like image 44
Taylor Leese Avatar answered Oct 01 '22 16:10

Taylor Leese


a ugly series of if,else if,else ?

like image 29
Pierre Avatar answered Oct 01 '22 16:10

Pierre