Eclipse3.7.1が今日正式にリリースされました。これでEclipse上でもJava7構文が大手を振って使えます。
さて、Java7で投入されたswitchにStringが使えるという構文。
switch(s){ case "abc": System.out.println("ok");break; case "bbb": System.out.println("no");break; }
これをjavacでコンパイルし、逆コンパイルすると以下の様になります。
byte byte0 = -1; switch(s1.hashCode()){ case 96354: if(s1.equals("abc")) byte0 = 0; break; case 97314: if(s1.equals("bbb")) byte0 = 1; break; } switch(byte0){ case 0: System.out.println("ok");break; case 1: System.out.println("no"); break; }
この様にswitchが2段階で行われます。
Eclipseでコンパイルすると様相が異なります。
switch((s1 = s).hashCode()){ default: break; case 96354: if(s1.equals("abc")) System.out.println("ok"); break; case 97314: if(s1.equals("bbb")) System.out.println("no"); break; }
JavaコンパイラーもEclipseみたいに書けばいいじゃんとか思ってたんだけど、よくよく考えてみたら話は単純だった。
以下の様な場合はjavacの様にしてないとうまくいかない(もしくはif文内部に無駄な処理ができる)
switch(s){ case "no"://hashCode=3521 System.out.println("no"); case "oP"://hashCode=3521 System.out.println("oP"); break; }
sがnoならば、
no
oP
と出力し、oPならばoPだけを出力する。noとoPのハッシュコードは3521で同じである。
この処理、if文で書くとnoの方にbreakがないから、すこし無理をした形にしなければならない。
しかし、javacの様な処理にしておけば、以下の様な素直な形にできる。
switch(s1.hashCode()){ case 3521: if(s1.equals("oP")) byte0=1; else if(s1.equals("no")) byte0=0; break; } switch(byte0){ case 0: System.out.println("no"); case 1: System.out.println("oP"); default: return; }
ちなみに、Eclipseを逆コンパイルすると、そのいびつな形が出てくる。
switch((s1=s).hashCode()){ default: break; case 3521: if(!s1.equals("no")){ if(!s1.equals("oP"))break; }else{ System.out.println("no"); } System.out.println("oP"); break; }
どっちが効率が良いのかまでは分からないけど、単純にSwitch文をSwitch文に直すという意味ではjavacの方が素直な実装になっているように見えるよね。
switch関連で読むと面白い記事
switch文は、case式の書き方によって、lookupswitch命令か、tableswitch命令のいずれかにコンパイルされる模様。