En-01: Enum の基本(定数セット)
Java の enum は、 関連する定数をひとつの型としてまとめる仕組みです。int 定数やString 定数と比べて 型安全で、IDE の補完やリファクタリングもしやすくなります。
いつ使うか
- 注文ステータス・支払方法・曜日など、取りうる値が決まっている定数セットを定義するとき
switch文やswitch式でケースを網羅させたいとき- 定数に独自のメソッドやフィールドを持たせたいとき(En-02 で詳しく解説します)
int 定数 / String 定数 / Enum の比較
| 特性 | int 定数 | String 定数 | Enum |
|---|---|---|---|
| 型安全性 | なし(任意の int を渡せる) | なし(任意の文字列を渡せる) | あり(定義した値のみ) |
| switch 全網羅チェック | なし | なし | あり(switch 式) |
| IDE 補完 | △ | △ | ◎ |
| メソッド追加 | 不可 | 不可 | 可能 |
サンプルコード
Java 8 から Enum に独自メソッドを追加できます。switch 文で Enum を使うと、コンパイラがすべてのケースを網羅しているか確認できます(警告が出ます)。
よくあるミス・注意点
Enum は == で比較する
Enum は同一インスタンスが保証されているため、== で比較できます。equals() でも動作しますが、 Enum の場合は == が慣例です。null との比較を== で行う場合は NullPointerException が発生しないので安全です。
ordinal() を DB に保存するのは危険
ordinal() は定義順の整数(0 始まり)を返しますが、 後から定数の順序を変更したり途中に挿入したりすると値がずれて既存データが壊れます。 DB に保存するときは name()(文字列)か、 En-02 で紹介する専用コードフィールドを使いましょう。
valueOf() に存在しない文字列を渡すと例外が発生する
Color.valueOf("UNKNOWN") のように 定義されていない文字列を渡すとIllegalArgumentException がスローされます。 外部入力(API レスポンス・ファイル)から変換する場合は try-catch するか、 事前に Arrays.stream(values()).anyMatch(...) で検証しましょう。
switch 式(Java 14+)では Enum の全ケースを必ず書く
switch 式で Enum を使う場合、全ケースを列挙すれば default は不要です。 ケースが不足していると「not exhaustive(網羅的でない)」というコンパイルエラーになります。 これにより、新しい Enum 定数を追加したときにコンパイルエラーで気付けるという安全性が得られます。
テストする観点
values()が全定数を定義順どおりに返すことordinal()が 0 始まりの定義順整数を返すこと(境界値: 先頭・末尾)valueOf()で正しい定数名を渡したとき、対応する Enum が返ることvalueOf()で存在しない文字列を渡したとき、IllegalArgumentExceptionがスローされることisWeekend()が SATURDAY・SUNDAY で true、それ以外で false を返すことisTerminal()が COMPLETED・CANCELLED で true、PENDING・PROCESSING で false を返すこと- Enum の == 比較が同じ定数では true、異なる定数では false を返すこと