En-02: Enum にメソッド・フィールドを追加
Java の Enum はフィールド・コンストラクタ・メソッドを持てます。 DB のコード値とのマッピングや、各定数に異なる処理を持たせるabstract メソッドなど、 実務でよく使われる設計パターンを解説します。
いつ使うか
- DB に保存する数値コードと画面表示名を Enum にまとめて管理したいとき
- 消費税率・送料計算など、定数ごとに異なる計算ロジックを持たせたいとき
- コード値から Enum に逆引きするファクトリメソッドが必要なとき
サンプルコード
Enum にコンストラクタ・フィールド・メソッドを追加することで、定数に付随するデータ(DB コード・表示名など)を一元管理できます。abstract メソッドを使うと各定数に異なる処理を持たせることができます。
よくあるミス・注意点
Enum のコンストラクタは必ず private
Enum のコンストラクタには明示的にアクセス修飾子を書かなくても private として扱われます。 外部から new PaymentMethod() を呼ぶことはできません。 Enum の定数はクラスロード時に JVM が一度だけ生成し、以後はシングルトンとして扱われます。
fromCode() のループ検索は要素数が増えると遅くなる
fromCode() はすべての定数をループで走査するため、 定数の数が多い・呼び出し頻度が高い場合はパフォーマンスに影響します。 頻繁に呼び出す場合は static フィールドとしてMap<Integer, PaymentMethod>をキャッシュしておくと O(1) で参照できます。
abstract メソッドを使うと各要素が匿名クラスになる
TaxRate の例のように abstract メソッドを持つ Enum では、各定数が匿名クラスとしてコンパイルされます。 クラスファイルが TaxRate$1.class・TaxRate$2.class のように増えます。 Java 14 以降では switch 式を使うほうがシンプルで読みやすいため、abstract メソッドはあまり使われなくなっています。
toString() を @Override すると valueOf() が動かなくなる場合がある
Enum の toString() はデフォルトでname() と同じ値を返します。 表示用に toString() を上書きすること自体は可能ですが、valueOf() は toString() ではなくname() を参照するため壊れません。 ただし、ログやデバッグで toString() の結果をvalueOf() に渡すようなコードは意図しない動作をするので注意しましょう。
テストする観点
fromCode()に各定数の code 値を渡したとき、対応する Enum が返ること(正常系・全件)fromCode()に存在しないコード値(例: 0、99)を渡したときIllegalArgumentExceptionがスローされること(異常系・境界値)TaxRate.STANDARD.apply(1000)が 1100.0 を返すことTaxRate.REDUCED.apply(1000)が 1080.0 を返すことTaxRate.apply(0)が 0 を返すこと(境界値: 価格 0 円)- 各
PaymentMethodのgetCode()・getDisplayName()・supportsRefund()が期待どおりの値を返すこと