Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the switchcase statement in Java works like this? [duplicate]

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.

like image 929
Ozil Avatar asked Jun 07 '13 04:06

Ozil


People also ask

Can switch case have duplicates?

The expression used in the switch statement must be integral type ( int, char and enum). In the Switch statement, all the matching case execute until a break statement is reached and Two case labels cannot have the same value.

How does a switch case work in Java?

The switch case in Java works like an if-else ladder, i.e., multiple conditions can be checked at once. Switch is provided with an expression that can be a constant or literal expression that can be evaluated. The value of the expression is matched with each test case till a match is found.

Can a switch statement be double in Java?

switch expression can't be float, double or boolean.

Can switch case Take 2 values?

With the integration of JEP 361: Switch Expressions in Java 14 and later, one can make use of the new form of the switch label using a comma between multiple values. People always mix up arrow labels and switch expressions. Sure they were introduced in the same JEP, but they are orthogonal features.


2 Answers

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.

like image 134
T.J. Crowder Avatar answered Oct 05 '22 13:10

T.J. Crowder


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();
 }

}

like image 36
Shahid Manzoor Bhat Avatar answered Oct 05 '22 15:10

Shahid Manzoor Bhat