tk555 diary

プログラミング、もしくはそれ以外のこと書きます。

[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における初期化の順番 | たむたむの日記 ...等々


...これハマると抜け出せないタイプの泥沼だった気がする。