4

I am using a single switch cases which will have more than 100 cases statement to be used. Are there any limit ?

The usage of cases are for the suggestions of my AutoCompleteTextView, android tutorial.

Here are part of my codes, ignore the Badrul.class they will be changed later.

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Toast;

public class Search extends Activity
{
    public void onCreate(Bundle savedInstanceSate)
    {
        final AutoCompleteTextView autoComplete;
        super.onCreate(savedInstanceSate);
        setContentView(R.layout.searchshop);

        autoComplete = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, shops);
        autoComplete.setAdapter(adapter); 
        autoComplete.setThreshold(1);
        autoComplete.setOnItemClickListener(new OnItemClickListener()
        {
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) 
        {
            int index=999;
            for(int i=0;i<shops.length;i++)
            {
                if(autoComplete.getText().toString().trim().equals(shops[i]))
                {
                    index=i;
                    break;
                }
            }

                switch(index)
                {
                case 0:
                    startActivity(new Intent(Search.this, Adidas.class));
                    break;

                case 1:
                    startActivity(new Intent(Search.this, Affin.class));
                    break;
                case 2:
                    startActivity(new Intent(Search.this, AlamArt.class));
                    break;
                case 3:
                    startActivity(new Intent(Search.this, AlAmin.class));
                    break;
                case 4:
                    startActivity(new Intent(Search.this, Anakku.class));
                    break;
                case 5:
                    startActivity(new Intent(Search.this, Anggerik.class));
                    break;
                case 6:
                    startActivity(new Intent(Search.this, Asiari.class));
                    break;
                case 7:
                    startActivity(new Intent(Search.this, AsterSpring.class));
                    break;
                case 8:
                    startActivity(new Intent(Search.this, Audrey.class));
                    break;
                case 9:
                    startActivity(new Intent(Search.this, Badrul.class));
                    break;
                case 10:
                    startActivity(new Intent(Search.this, Badrul.class));
                    break;
                case 11:
                    startActivity(new Intent(Search.this, Badrul.class));
                    break;
                default:
                    Toast.makeText(Search.this, "Invalid Selection", Toast.LENGTH_SHORT).show();
                }
            }
            });

        }
static final String[] shops = new String[]
            {
                "Adidas", "Affin Bank ATM", "Alam Art Gallery", "Al Amin Kids", "Anakku", "Anggerik", "Asiari", 
                "Aster Spring", "Audrey", "Badrul Songket", "Bata"};
}
Kenneth Lhv
  • 558
  • 2
  • 6
  • 16
  • 6
    I wonder if is there a better solution to your problem... can you post some code? – davioooh Jan 27 '12 at 09:58
  • Just make sure there is no either approach like using [OOP](http://en.wikipedia.org/wiki/Object-oriented_programming) – Adel Boutros Jan 27 '12 at 09:59
  • I don't know of any technical limit that would restrict you to have more than 100 cases (unless you have millions of them, in which case some other limits like memory, code size etc. might take effect). However, if you have that many cases it might be worthwhile to question the design and look for some better option. In that case you might want to give some more information in the switch statement. – Thomas Jan 27 '12 at 10:01
  • as Thomas said change in design may solve ur problem – Balaswamy Vaddeman Jan 27 '12 at 10:03
  • 2
    Might be a [XY Problem](http://www.perlmonks.org/?node_id=542341)? – Marcelo Jan 27 '12 at 10:04
  • I think inheritance may help you... :) – davioooh Jan 27 '12 at 10:10
  • @DavidC. if you dont mind to point me, i am new in programming. :O – Kenneth Lhv Jan 27 '12 at 10:12

7 Answers7

7

The code will become unmanageable before you hit any limit that Java imposes.

Have you considered refactoring the code? Depending on what the switch statement is designed to achieve you could either:

So in your case, you would be better off defining a static Map of index values to Classes:

public class MyClass
{
    private static final Map<Integer, Class> LOOKUP = 
      new HashMap<Integer, Class>(...);
    static
    {
      LOOKUP.put(0, Adidas.class);
      LOOKUP.put(1, Affin.class);
      ...
    }

    public void onItemClick(...)
    {
      ...
      // Replace switch statement with:
      if (LOOKUP.containsKey(index))
      {
        startActivity(new Intent(Search.this, LOOKUP.get(index)));
      }
      else
      { 
        Toast.makeText(Search.this, 
                       "Invalid Selection", 
                       Toast.LENGTH_SHORT).show();
      }
    }
    ...
  }

This makes the code in onItemClick() easier to read. You could go one step further and define a private startActivity() method that takes the index to be used and contains all the switch statement replacement code.

Andy
  • 8,870
  • 1
  • 31
  • 39
  • I guess you are stating that to define the Map m = new HashMap(...); within the onItemClick method? Sorry but i am new and your solution seem to be complicated. If you dont mind to edit my code with your concept. – Kenneth Lhv Jan 27 '12 at 10:33
  • The Map is probably best defined as a private static final field in the class that contains your existing code. That way it doesn't need to be created every time the onItemClick method is called. I'll update my answer to make this clearer. – Andy Jan 27 '12 at 10:45
4

Switch works fine with byte, short, char, and int. So you have the limitation of int values + default. From here

But I suggest to think more on architecture. It is better to organize some interface 'performer' and implement some number of that performer (could be as inner classes). Then you only need to have an array(map) where you will have the conditions and instances of this performers. The idea is to separate the data from algorithm.

Also yo may try to find other patterns for that

Fedor Skrynnikov
  • 5,521
  • 4
  • 28
  • 32
4

There is a limit imposed on the maximum method length: Maximum size of a method in java?

Otherwise, as an example, a switch with 1000 cases of the form

casen: System.out.println(n); break;

seems to work. The generated bytecode uses a tableswitch instruction, which means it shouldn't even be inefficient.

Of course, unless it's automatically generated code, this will be frowned upon.

Think of alternatives, such as:

  • a map/array of values (if your cases just return or produce a value of some kind);
  • a map/array of objects that will run the necessary code (depending on the exact conditions, you might end up with less code this way).

Edit:

Looking at your code, it seems, since all your case statements run the exact same type of code, all you need is a Class[] accessed by index, something like:

Class[] myArray = new Class[...];
myArray[0] = Adidas.class;
//...

//instead of the switch
startActivity(new Intent(Search.this, myArray[index])); 

And of course, it would be prettier if there were a way to produce those classes some other way, say if you had Adidas and Affin objects, and you ran getClass() on them, or if you had a list of their names and could use Class.forName.

Community
  • 1
  • 1
Vlad
  • 18,195
  • 4
  • 41
  • 71
1

Or you can have a look at the strategy pattern. For example:

If it looks like this now:

switch (calculation type)
{
   case: Fibonacci { ... }
   case: Pithagoras { ... }
   ...
   case 104 : { ... }
}

You can refactor it using the strategy pattern maybe like this:

CalculationStrategy strategy = strategyFactor.getStrategy(calculation type);
strategy.doCalculation;

Happy coding! Dave

dbalakirev
  • 1,918
  • 3
  • 20
  • 31
0

When implementing switches many optimisations can be made for performance, otherwise you have to list through all the switches till it matches.

What I would do here, is have a main set of switches for the first character then nested switches inside, therefore if the choice was z it doesn't have to loop check every name first

switch(FIRSTCHAR){
case A: switch(index){
        case 0: ..... break;
        etc

        }
break;

case B://do the same
}

Another way is to break your switch statement up into smaller equal sized statements. This is faster due the way the bytecode is compiled (ref Java performance tuning - shirazi)

Sam Palmer
  • 1,675
  • 1
  • 25
  • 45
0

One possibel appraoch is to move/remodel that code to "Chain of Responsibility patter given that those switch statements are not simple return, some processing is involved on them and so on.

I believe you dont have use case of Guava Ranges too (In other words you are having each case a descret one, not a common processing on two (more than one) case.

manocha_ak
  • 904
  • 7
  • 19
0

I don't know exactly what your startActivity() method do, don't even know how the Intent object is implemented, but I think an alternative way to solve your issue could be:

  • Define a super-class or interface called Shop (for example);
  • Inherit all your classes like Adidas or Affin from it;
  • Call the specific implementation of startActivity() method for each class;

For example:

public interface Shop
{
    void startActivity(Intent i);
}

Then, for each class...

public class Adidas implements Shop
{
    public Adidas(){
        // ...
    }

    public void startActivity(Intent i)
    {
        // specific implementation
    }
}

Finally, in your client code

Shop[] shops = new Shop[]{ new Adidas(), new Affin(), ... };

for (Shop shop : shops)
{
   shop.startActivity(new Intent(Search.this));
}
davioooh
  • 23,742
  • 39
  • 159
  • 250