C# と Java の列挙型の違い
はじめに
某イベントで Effective Java の訳者として有名な柴田さんとお話する機会があり、長年の疑問が解決したのでメモ。
それぞれの列挙型
C# の場合
C# の列挙型はとてもシンプルです。C 言語の enum
と同じです。
public enum Gender
{
NotKnown = 0,
Male = 1,
Female = 2,
NotApplicable = 9
}
こんなかんじで使えます。
if (customer.Gender == Gender.Female)
{
// 女性の場合は割引金額
return 1500;
}
return 1800;
整数で書くと if (customer.Gender == 2)
のようになるので、仕様書をひっくり返して 2
ってなんだっけ? ってなりますね。列挙型のおかげでいろいろ助かるわけです。
Java の場合
Java の列挙型は C# のそれと比較して強力です。後発の C# の方が Java より強力であることのほうが多いのですが、列挙型は Java の方が強力な機能の一つです。
public enum Gender {
NotKnown(0, "不明"),
Male(1, "男性"),
Female(2, "女性"),
NotApplicable(9, "判別不能");
private final int id;
private final String name;
private Gender(int id, String name) {
this.id = id;
this.name = name;
}
public int getFee() {
if (this.equals(Gender.Female)) {
// 女性の場合は割引
return 1500;
}
return 1800;
}
@Override
public String toString() {
return this.name;
}
}
C# と違い、Java の列挙型はクラスそのものです。C# では料金を性別で切り替えるのを列挙型の外に書きましたが、Java では列挙型の中に書けます。
こういう区分で処理を切り替えることはよくありますが、C# のような単純な列挙型の場合は、処理の切り替えを探すのが一苦労です。Java の用に列挙型に書ければ、すぐに見つかるわけですね。
なんで C# の列挙型はしょぼいの?
できないものはしょうがないのであまり調べたことはなかったんですが、柴田さんから納得できる理由をもらいました。
C# は 1.0 (2002) の時点で列挙型は組み込まれていました。対する Java はと言うと... その時点では列挙型がなかったんですね。つまり列挙型に関しては Java の方が後発で、C# よりいい仕様を取り入れることができたってことのようです。
ちなみに、Java への列挙型の導入は Java 5.0 (2004) からです。
よくよく考えると、高機能な列挙型があるのにもかかわらず、よく使われる Calendar.DAY_OF_MONTH
などは全て整数で列挙型ではありません。その頃にはなかったんですね。全く気が付きませんでした。
おまけ
C# でも対抗はできる
C# の (厳密には .NET の) 列挙型はオブジェクトではないので、Java と同じにはなりません。しかし、拡張メソッドを使うと同じようなことはできます。
public static class GenderExtensions
{
public int GetFee(this Gender gender)
{
if (gender == Gender.Female)
{
return 1500;
}
return 1800;
}
}
このクラスを Gender
列挙型と同じ名前空間で同じファイルに書けば Java とあんまりかわりません!
ただ、ToString()
メソッドとかはこの方法が使えないんですよね...
そもそも必要なの?
確かに Java の列挙型は便利なんですけど、ないならないでっていうお話も。
処理が複雑な場合はストラテジーパターン (もしくはステートパターン) を利用したほうがすっきりするのはよく知られています。
また、金額をデータベースから読み込みたいとなると列挙型には書きづらくなります。
ないならないでなんとかなるんです。
でも、ちょっとした列挙型とか書くときは Java が羨ましくなるのでした!