[Java]enumの逆引きをバグらせた
ググった限りenumの逆引きは実際によくやる類のものらしい。
実装すると以下のようになる。
public enum OS { WINDOWS("win"), MAC("mac"); final String s; private OS(String s) { this.s = s; } //キャッシュしておく private static Map<String, OS> cache = new HashMap<>() { { for (OS os : values() /*<-ここ*/) { put(os.s, os); } } } public static Optional<OS> resolve(String s) { return Optional.ofNullable(cache.get(s)); } }
実は上のコードにはバグがある。(/*ここ*/部分)
cacheの生成時、インスタンスイニシャライザの中のvaluesは実装時に意図したOS.values()(返り値OS[])ではなくHashMap.values()(返り値Collection
返り値が配列とCollectionのためコンパイルは通るが、その時点ではcacheの中身は空なのでバグになる。
(正直Javaパズルに入れる一歩手前くらいの難しさはあると思う)
理由が分かると簡単なミスで恥ずかしいのでQiitaじゃなくて自分のブログに書いておく。
よく考えるとstaticであるcacheの初期値が入る時点でOS.values()を呼んでいるので、enumを普通のclass的な何かだと思って脳内デバッグするとおかしなことになる。
これはenumとclassでstatic変数が初期化されるタイミングが違うため。
JavaのEnumにおける初期化の順番 | たむたむの日記 ...等々
...これハマると抜け出せないタイプの泥沼だった気がする。