benf.org : other : cfr : Java 7 Switch On String |
Since this is just about usable now, I thought I'd try it with some of the java 7 features. I had wondered how switch on string worked. I was just about right, (like so much in java-land, it's all syntactic sugar) but it still leaves me feeling rather sad.
(This isn't a secret - the original proposal is here, but, like I mention elsewhere, reverse engineering this stuff is fun!)int test0(String s) { switch (s) { default: System.out.println("Test"); break; case "BB": // BB and Aa have the same hashcode. return 12; case "Aa": case "FRED": return 13; } System.out.println("Here"); return 0; }
With the nostringswitch parameter, we can tell CFR not to re-sugar string switches. This lets us see the code that javac has created - effectively it's creating a hardcoded hashtable with chaining for the first switch...
public int test0(String s) { unnamed_local_s_2 = s; unnamed_local_s_3 = -1; switch (unnamed_local_s_2.hashCode()) { case 2112: { if (unnamed_local_s_2.equals("Aa")) { unnamed_local_s_3 = 2; break; } if (!(unnamed_local_s_2.equals("BB"))) break; unnamed_local_s_3 = 1; break; } case 2166379: { if (!(unnamed_local_s_2.equals("FRED"))) break; unnamed_local_s_3 = 3; } } switch (unnamed_local_s_3) { default: { System.out.println("Test"); break; } case 1: { return 12; } case 2: case 3: { return 13; } } System.out.println("Here"); return 0; }
It relies on (quite reasonable) the fact that since the buggy early version of hashcode was fixed, java's String hashcode has an explicit algorithm, which is fair enough. But it needs the two pass switch to handle fallthrough and collisions... :P
If you don't specify --nostringswitch, as of 0_6, cfr will resugar the switch, and output the following
public int test0(String s) { switch (s) { default: { System.out.println("Test"); break; } case "BB": { return 12; } case "Aa": case "FRED": { return 13; } } System.out.println("Here"); return 0; }
For interests sake, here is javap's output
public int test0(java.lang.String); Code: 0: aload_1 1: astore_2 2: iconst_m1 3: istore_3 4: aload_2 5: invokevirtual #2 // Method java/lang/String.hashCode:()I 8: lookupswitch { // 2 2112: 36 2166379: 64 default: 75 } 36: aload_2 37: ldc #3 // String Aa 39: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 42: ifeq 50 45: iconst_2 46: istore_3 47: goto 75 50: aload_2 51: ldc #5 // String BB 53: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 56: ifeq 75 59: iconst_1 60: istore_3 61: goto 75 64: aload_2 65: ldc #6 // String FRED 67: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 70: ifeq 75 73: iconst_3 74: istore_3 75: iload_3 76: tableswitch { // 1 to 3 1: 115 2: 118 3: 118 default: 104 } 104: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 107: ldc #8 // String Test 109: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 112: goto 121 115: bipush 12 117: ireturn 118: bipush 13 120: ireturn 121: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 124: ldc #10 // String Here 126: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 129: iconst_0 130: ireturn
Last updated 02/2013 |