導入
こんにちは、もんすんです。
今回は、enum
のordinal()
メソッドを使う機会があったので、それについて執筆してみました。
Javaのenum
は便利ですが、その使い方次第でコード保守が難しくなることがあります。
今回は、enum
と整数値を安全に関連付ける方法を解説していきます。
ordinal()
メソッドについて
ordinal()メソッドとは
ordinal()
メソッドは、enum
定数の定義順序を表すインデックス値を返してくれるメソッドです。
このインデックスはenum
の最初の定数を0
とし、それ以降の定数は1ずつ増加させた値になります。
サンプル
以下はordinal()
メソッドを使用する簡単なサンプルです。
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
}
public class OrdinalExample {
public static void main(String[] args) {
for (Day day : Day.values()) {
System.out.println(day + ": " + day.ordinal());
}
}
}
このコードの出力は、以下のようになります。
MONDAY: 0
TUESDAY: 1
WEDNESDAY: 2
THURSDAY: 3
FRIDAY: 4
orginal()
の使用目的
-
ordinal()
は主に、enum
定数の相対的な位置を参照する際に役立つ - ソートや順序比較が必要な場合において、インデックスとして活用できる
しかし、ordinal()
をビジネスロジックに組み込むことは多くの場合推奨されません。
なぜordinal()
のビジネスロジックへの適用は危険なのか?
では、ordinal()
の利用における問題について考えていきます。
ここでは、以下のコードを考えていきます。
public enum Ensemble {
SOLO, DUET, TRIO, QUARTET
}
public int numberOfMusicians() {
return ordinal() + 1;
}
このコードでは、ordinal()
を利用して、定数に人数を割り当てています。
しかし、この方法には以下のような問題が潜んでいます。
-
定数の並び順に依存する
定数の順序を変更したり、新しい定数を途中に追加すると、割り当てられる値が変わってしまいます。 -
重複する値を持つ定数を定義できない
例えば、8人編成の「OCTET」が追加されたとします。
それと同じ人数で「DOUBLE_QUARTET」を追加したい場合、同じ値を割り当てる方法がありません。 -
途中の値をスキップできない
例えば、12人編成の「TRIPLE_QUARTET」を追加したい場合、11人編成のダミー定数を無理やり追加する必要があります。
ではどうするか??
安全な方法:インスタンスフィールドを使う
ordinal()
を使わず、enum
にインスタンスフィールドを持たせることで、値の安全な管理が可能になります。
以下はその例になります。
public enum Ensemble {
SOLO(1),
DUET(2),
TRIO(3),
QUARTET(4),
QUINTET(5),
SEXTET(6),
SEPTET(7),
OCTET(8),
DOUBLE_QUARTET(8),
NONET(9),
DECTET(10),
TRIPLE_QUARTET(12);
private final int numberOfMusicians;
// コンストラクタ
Ensemble(int size) {
this.numberOfMusicians = size;
}
// 値を取得するメソッド
public int numberOfMusicians() {
return numberOfMusicians;
}
}
この方法のメリット
-
順序変更に強い
定数の順序を変更しても、numberOfMusicians
の値には影響しません。 -
重複する値を持つ定数を定義できる
例えば「OCTET」と「DOUBLE_QUARTET」に同じ値(8)を割り当てることができています。 -
途中の値をスキップできる
必要な値(例えば12)だけを直接設定でき、使わない値(例えば11)をスキップ可能です。
ordinal()
の正しい使い方
Javaの公式ドキュメントでは、ordinal()
は特殊なデータ構造(EnumSet
やEnumMap
)で使用するために設計されているとされています。
具体的には、enum
を配列のインデックスとして扱う場合などに適しています。
...とのことでした。
それ以外の目的でordinal()
を使うのは避けたほうがよさそうですね。
最後に
ordinal()
メソッドは手軽で便利に見える一方で、値の関連付けに使用することは避けたほうが良いことを例を示しながら紹介しました。
代わりに、enum
にインスタンスフィールドを追加し、値を明示的に管理する方法を採用しましょう!
ぜひ今回の内容が誰かの役に立てば、と思います!