String switch implementation

by Mikhail Vorontsov

This article covers the implementation details of String switch introduced in Java 7. It is a syntactic sugar on top of the normal switch operator.

Suppose you have the following method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public int switchTest( final String s )
{
    switch ( s )
    {
        case "a" :
            System.out.println("aa");
            return 11;
        case "b" :
            System.out.println("bb");
            return 22;
        default :
            System.out.println("cc");
            return 33;
    }
}
public int switchTest( final String s )
{
    switch ( s )
    {
        case "a" :
            System.out.println("aa");
            return 11;
        case "b" :
            System.out.println("bb");
            return 22;
        default :
            System.out.println("cc");
            return 33;
    }
}

It is converted by javac into the following code (decompiled back into Java):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public int switchTest(String var1) {
    byte var3 = -1;
    switch(var1.hashCode()) {
    case 97:
        if(var1.equals("a")) {
            var3 = 0;
        }
        break;
    case 98:
        if(var1.equals("b")) {
            var3 = 1;
        }
    }
 
    switch(var3) {
    case 0:
        System.out.println("aa");
        return 11;
    case 1:
        System.out.println("bb");
        return 22;
    default:
        System.out.println("cc");
        return 33;
    }
}
public int switchTest(String var1) {
    byte var3 = -1;
    switch(var1.hashCode()) {
    case 97:
        if(var1.equals("a")) {
            var3 = 0;
        }
        break;
    case 98:
        if(var1.equals("b")) {
            var3 = 1;
        }
    }

    switch(var3) {
    case 0:
        System.out.println("aa");
        return 11;
    case 1:
        System.out.println("bb");
        return 22;
    default:
        System.out.println("cc");
        return 33;
    }
}

The generated code consists of 2 parts:

  • Translation from String into a distinct int for each case, which is implemented in the first switch statement.
  • The actual switch based on int-s.

The first switch contains a case for each distinct String.hashCode in the original String switch labels. After matching by hash code, a string is compared for equality to every string with the same hash code. It is pretty unlikely that 2 strings used in switch labels will have the same hash code, so in most cases you will end up with exactly one String.equals call.

After seeing the generated code, it becomes clear why you can not use null as a switch label: the first switch starts from calculating the hashCode of the switch argument.

What can we say about the performance of the underlying int switch? As you can find in one of my earlier articles, a switch is implemented as a fixed map with a table size of approximately 20 (which is fine for most of common cases).

Finally, we should note that String.hashCode implementation has implicitly became the part of the Java Language Specification after it was used in the String switch implementation. It can no longer be changed without breaking the .class files containing String switch, which were compiled with the older versions of Java.


Leave a Reply

Your email address will not be published. Required fields are marked *