18

In Java 7 a string object can be in the expression of a switch statement. Can someone explain the below statement from official documentation?

The Java compiler generates generally more efficient bytecode from switch statements that use String objects than from chained if-then-else statements.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
user1428716
  • 2,078
  • 2
  • 18
  • 37

4 Answers4

42

Java Code

Having two versions of a class, e.g.

With if-then-else:

public class IfThenElseClass {
    public static void main(String[] args) {
        String str = "C";
        if ("A".equals(str)) {

        } else if ("B".equals(str)) {

        } else if ("C".equals(str)) {

        }
    }
}

With switch:

public class SwitchClass {
    public static void main(String[] args) {
        String str = "C";
        switch (str) {
            case "A":
                break;
            case "B":
                break;
            case "C":
                break;
        }
    }
}

Bytecode

Let's take a look at the bytecode. Getting the bytecode for if-then-else version:

Compiled from "CompileSwitch.java"
public class CompileSwitch {
  public CompileSwitch();
    Code:
       0: aload_0
       1: invokespecial #8  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String C
       2: astore_1
       3: ldc           #18 // String A
       5: aload_1
       6: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
       9: ifne          28
      12: ldc           #26 // String B
      14: aload_1
      15: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      18: ifne          28
      21: ldc           #16 // String C
      23: aload_1
      24: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      27: pop
      28: return
}

Getting the bytecode for switch version:

Compiled from "CompileSwitch.java"
public class CompileSwitch {
  public CompileSwitch();
    Code:
       0: aload_0
       1: invokespecial #8 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String C
       2: astore_1
       3: aload_1
       4: dup
       5: astore_2
       6: invokevirtual #18 // Method java/lang/String.hashCode:()I
       9: lookupswitch  { // 3
                    65: 44
                    66: 56
                    67: 68
               default: 77
          }
      44: aload_2
      45: ldc           #24 // String A
      47: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      50: ifne          77
      53: goto          77
      56: aload_2
      57: ldc           #30 // String B
      59: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      62: ifne          77
      65: goto          77
      68: aload_2
      69: ldc           #16 // String C
      71: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      74: ifne          77
      77: return
}

Conclusion

  • In the first version compares the string by calling the equals method for each condition, until it is found.

  • In the second version is obtained first hashCode of the string. Then this is compared with the values ​​hashCode each case. See the lookupswitch. If any of these values ​​is repeated just happens to run the code for the case. Otherwise, call the equals method of the cases tied. This is much faster than ever call the equals method only.

Paul Vargas
  • 41,222
  • 15
  • 102
  • 148
3

switch on strings can be faster for the same reason why a lookup in a hash set of strings may be faster than a lookup in a list of strings: you can do a lookup in O(1) rather than in O(N), where N is the number of strings.

Recall that switch is more efficient than a chain of if-then-else statements because it is a calculated jump: an offset in code is calculated based on the value, and then the jump to that offset is executed. Java can pull a similar trick on strings using the mechanism similar to that employed in hash maps and hash sets.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

It's more efficient something like:

switch(yourString) {
    case "text1":
        // your code
        break;
    case "text2":
        // etc.
}

than the correspondent:

if (yourString.equals("text1")) {
     // your code
} else if (yourString.equals("text2")) {
     // etc.
}
javatutorial
  • 1,916
  • 15
  • 20
-1

i guess what it means, or what i understand is that the bytecode (when you compile your java class) that created from an switch statement using string is faster and more efficient than the bytecode that is created from an if-else statement using string. both can do the same job, bit switch is apparently more efficient.

switch (str) {
            case "A":  
                     // do something
                     break;
            case "B":
                     // do something
                     break;
            default: 
                     //do something
                     break;
}

is better than

if(str.equals("A")) {
//do something
} else if(str-equals("B")) {
//do something
} else {
//do something
}
tagtraeumer
  • 1,451
  • 11
  • 19