Java7のString Switch
家で試してみました。
サンプルで書いたコード。
"1a"と"2B"は同一ハッシュコード1616です。
private String test1(String val) { String ret = null; switch (val) { case "1a": ret = "match 1a"; break; case "2B": ret = "match 2B"; break; default: ret = "match default"; } return ret; }
indigoのclass file editorで見たものに、補足を書き足しました。
private java.lang.String test1(java.lang.String val); 0 aconst_null // nullをオペランドスタックに積む 1 astore_2 [ret] // オペランドスタックから取り出し、2番目のローカル変数に入れる 2 aload_1 [val] // 1番目のローカル変数を、オペランドスタックに積む 3 dup // オペランドスタックの一番上に積まれてる参照をもう一個作り、積む。 4 astore_3 // オペランドスタックから取出し、3番目のローカル変数に入れる。 5 invokevirtual java.lang.String.hashCode() : int [29] // オペランドスタックから取り出し、valのハッシュコード取得 8 lookupswitch default: 61 // ハッシュコードの評価。1616なら28へ、それ以外は61へ飛ぶ。 case 1616: 28 28 aload_3 // 3番目のローカル変数を、オペランドスタックに積む。 29 ldc[35] // ベタ書きの"1a"をオペランドスタックに積む。 31 invokevirtual java.lang.String.equals(java.lang.Object) : boolean [37] // "1a".equals(val) 34 ifne 49 // trueなら49へ。falseなら37に続く。 37 aload_3 // 3ばんめのローカル変数を、オペランドスタックに積む。 38 ldc [48] // ベタ書きの"2B"をオペランドスタックに積む 40 invokevirtual java.lang.String.equals(java.lang.Object) : boolean [37] "2B".equals(val) 43 ifne 55 // trueなら55へ。falseなら46に続く 46 goto 61 // ハッシュコードがマッチしたが、どの定数にも合致せず、defaultの飛び先である61へ 49 ldc [50] // "1a"に合致した際の処理。文字列をオペランドスタックに積む 51 astore_2 [ret] // オペランドスタックから取り出し、2番目のローカル変数に代入 52 goto 64 // 64へ 55 ldc [52] // "2B"に合致した際の処理。文字列をオペランドスタックに積む 57 astore_2 [ret] // オペランドスタックから取り出し、2番目のローカル変数に代入 58 goto 64 // 64へ 61 ldc [54] // defaultになった際の処理。文字列をオペランドスタックに積む 63 astore_2 [ret] // オペランドスタックから取り出し、2番目のローカル変数に代入 64 aload_2 [ret] // returnの処理。2番目のローカル変数をオペランドスタックに積む 65 areturn // オペランドスタックから取り出してreturn。 Line numbers: [pc: 0, line: 27] [pc: 2, line: 28] [pc: 49, line: 30] [pc: 52, line: 31] [pc: 55, line: 33] [pc: 58, line: 34] [pc: 61, line: 36] [pc: 64, line: 38] Local variable table: [pc: 0, pc: 66] local: this index: 0 type: StringSwitch [pc: 0, pc: 66] local: val index: 1 type: java.lang.String [pc: 2, pc: 66] local: ret index: 2 type: java.lang.String Stack map table: number of frames 5 [pc: 28, append: {java.lang.String, java.lang.String}] [pc: 49, same] [pc: 55, same] [pc: 61, same] [pc: 64, chop 1 local(s)]
基本的には言語使用が変更され、コンパイラが賢くなったということですね。
コンパイラが勝手にローカル変数(index 3)を作ることがあるのだと知りました。
そしてLocal variable tableには入ってない。
case文に使用出来るのは定数表現でなければならないとコンパイラーがエラーを出力するのだが、
どのへんまで許容されるか探りを入れてみた。
代入を遅らせて宣言するfinal String var;はどうやらNGのようだ。
代入がメソッドの戻り値でもダメ(finalだけでは判断されない)。final String var = getVar();
クラス変数、インスタンス変数、ローカル変数のどれでも構わない。