10

Why the switch case statement in Java only takes integer, short, byte and character only and not other data types? What could be the benefit? Please explain in detail.

7
  • 6
    It also accepts Strings and Enums since JDK 1.7. Commented Jun 7, 2013 at 4:39
  • 2
    This is a language requirement. Under Java 7, it now supports String and since enum was introduced, it also supports enum. The question really comes down to how would you define a case for an arbitrary object? Commented Jun 7, 2013 at 4:39
  • @MadProgrammer Well you can create an arbitrary object and use equals to match against each case I guess. Commented Jun 7, 2013 at 4:41
  • @Thihara But what about toString? I think the problem is do you want to match the equality of one object to another or a property of the object? Commented Jun 7, 2013 at 4:43
  • 3
    @EdwinDalorzo switch accepted enums since enums were added (Java 5 , which was 2004) Commented Jun 7, 2013 at 4:51

2 Answers 2

16

Usually language design questions boil down to "because that's the way the designers decided to do it." This is just another of those times.

But Java has some origins in C, which did the same thing, and in the 80's that decision was explained to me as being because then the compiler could turn the switch into a jump table: Basically, each block of code's address is put in a table and the switch becomes a range check followed by a table lookup (usually indexing into an array or at least linked list of arrays) using the value you pass in to get the address, and then jump to that address. Only integers make sense in that scenario. Remember that computers weren't always as fast as they are now. C was designed in the early 70's based on work in the late 60's, when computers were much slower.

Some languages in the same syntactic tradition as Java and C, such as JavaScript, make the switch just another way of writing if...else/if...else and don't limit the type being checked to integral types, perhaps because, being designed in the 90's, that became a realistic option. Or perhaps just because the designer of JavaScript (Brendan Eich) preferred it that way.


Below, Baadshah asks:

Out of curiosity : Then now how its supporting Strings ??? can you please give some sort of idea ?

First, let's step back and look at the int case:

  num = Integer.parseInt(args[0]);
  switch (num) {
      case 1:
          System.out.println("You used the special value one");
          break;
      case 42:
          System.out.println("You used the special value forty-two");
          break;
      case 67:
          System.out.println("You used the special value sixty-seven");
          break;
      default:
          System.out.println("You used the a non-special value " + num);
          break;
  }

That produces bytecode like this:

 19: iload_2       
 20: lookupswitch  { // 3
                1: 56
               42: 67
               67: 78
          default: 89
     }
 56: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 59: ldc           #9   // String You used the special value one
 61: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 64: goto          114
 67: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 70: ldc           #11  // String You used the special value forty-two
 72: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 75: goto          114
 78: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 81: ldc           #12  // String You used the special value sixty-seven
 83: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 86: goto          114
 89: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 92: new           #13  // class java/lang/StringBuilder
 95: dup           
 96: invokespecial #14  // Method java/lang/StringBuilder."":()V
 99: ldc           #15  // String You used the a non-special value 
101: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
104: iload_2       
105: invokevirtual #17  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
108: invokevirtual #18  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
111: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

We can see the table lookup on the int in action.

So how do you do that with strings? Well, one answer would be to just turn the switch into an if...else if...else structure. But they did something more clever than that: They used the hashcode to optimize, and then used equals to protect against collisions:

  switch (str) {
      case "abc":
          System.out.println("You used the special value 'abc'");
          break;
      case "def":
          System.out.println("You used the special value 'def'");
          break;
      case "ghi":
          System.out.println("You used the special value 'ghi'");
          break;
      default:
          System.out.println("You used the a non-special value '" + str + "'");
          break;
  }

becomes:

124: aload         4
126: invokevirtual #19  // Method java/lang/String.hashCode:()I
129: lookupswitch  { // 3
            96354: 164
            99333: 180
           102312: 196
          default: 209
     }
164: aload         4
166: ldc           #20  // String abc
168: invokevirtual #21  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
171: ifeq          209
174: iconst_0      
175: istore        5
177: goto          209
180: aload         4
182: ldc           #22  // String def
184: invokevirtual #21  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
187: ifeq          209
190: iconst_1      
191: istore        5
193: goto          209
196: aload         4
198: ldc           #23  // String ghi
200: invokevirtual #21  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
203: ifeq          209
206: iconst_2      
207: istore        5
209: iload         5
211: tableswitch   { // 0 to 2
                0: 236
                1: 247
                2: 258
          default: 269
     }
236: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
239: ldc           #24  // String You used the special value 'abc'
241: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
244: goto          299
247: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
250: ldc           #25  // String You used the special value 'def'
252: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
255: goto          299
258: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
261: ldc           #26  // String You used the special value 'ghi'
263: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
266: goto          299
269: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
272: new           #13  // class java/lang/StringBuilder
275: dup           
276: invokespecial #14  // Method java/lang/StringBuilder."":()V
279: ldc           #27  // String You used the a non-special value '
281: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
284: aload_3       
285: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
288: ldc           #28  // String '
290: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
293: invokevirtual #18  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
296: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

See what they did there? It's basically two switches now: One to get a unique number for each case based on the hashcode (but double-checking with equals), and then the second to dispatch.

Sign up to request clarification or add additional context in comments.

3 Comments

Out of curiosity : Then now how its supporting Strings ??? can you please give some sort of idea ?
@Baadshah: A very good question! I've updated to address it.
Thanks you Crowder.Awsome explanation for a simple comment.
1

JDK6 switch statement worked on char, byte, int primitive data types and enum. In JDK 7 they realised that java.lang.String is also a constant and has been added to the list of data types supported by a switch statement.

For example the following code works fine in JDK7.

 public static void OpenSource(String language) 
{
 switch (language) {
 case "PERL":
   System.out.println("PERL");
   break;
 case "Python":
   System.out.println("Python");
   break;
 case "Ruby":
   System.out.println("Ruby");
   break;
 case "PHP":
   System.out.println("PHP");
   break;
  default:
   throw new IllegalArgumentException();
 }

}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.