1. 導入
プログラミングでは、あらかじめ決まっていて数が限られている選択肢を扱うことがよくあります。例: 曜日、信号機の色、ゲームの難易度、注文のステータス。それぞれの候補は通常、固定の値で表されます。ここで本題の列挙型(enum)に近づきます。
列挙型は、名前付き定数の集合を宣言できる特別なデータ型です。
enum は、仕切られた箱にラベルが並んでいるイメージで、各ラベルは数値に結び付いた一意の名前です。
enum の主な利点:
- コードが読みやすくなり、自己文書化されます。
- 0、1、2 といった「マジックナンバー」の代わりに、DayOfWeek.MONDAY や TrafficLight.RED のような表現力のある名前を使えます。
- 不正な値を代入しようとするとコンパイラがエラーにしてくれます。
- 各要素の背後には…実は普通の整数が紐付いています!(この点は後述します。)
enum の宣言構文
// 列挙型の一般的な宣言テンプレート
public enum Imya
{
KONSTANTA1 ,
KONSTANTA2 ,
KONSTANTA3
}
Java で列挙型を宣言するのはとても簡単です。基本例は次のとおりです:
// ファイル DayOfWeek.java
public enum DayOfWeek {
MONDAY, // 0
TUESDAY, // 1
WEDNESDAY, // 2
THURSDAY, // 3
FRIDAY, // 4
SATURDAY, // 5
SUNDAY // 6
}
説明:
- キーワード enum はコンパイラに「これは列挙型だ」と伝えます。
- 波括弧内に候補(定数)名をカンマ区切りで並べます。
- 名前は UPPER_SNAKE_CASE(すべて大文字、単語はアンダースコア区切り)で書くのが一般的です。
enum はどこに宣言できる?
- 別ファイル(DayOfWeek.java)。
- クラス内(そのクラスだけで使う列挙にしたい場合)。
- メソッド内(ただし、そのようにすることは稀)。
2. コードでの enum の使い方
enum 型変数の宣言:
DayOfWeek today = DayOfWeek.MONDAY;
これで today は DayOfWeek に宣言された値のいずれかしか取りません。
switch での使用例
switch (today)
{
case MONDAY:
System.out.println("ああ、月曜日…");
break;
case FRIDAY:
System.out.println("やった、金曜日!");
break;
default:
System.out.println("普通の日。");
}
重要な違い: 変数の型がコンパイラに既に分かっている場合、case には(接頭辞なしで)定数名だけを書きます。
enum の全値を走査する
各 enum にはすべての値を返す静的メソッド values() があります:
for (DayOfWeek day : DayOfWeek.values())
{
System.out.println(day);
}
メニューの表示、検証、候補の生成などにとても便利です。
3. enum のメソッド: name()、ordinal()、valueOf()
Java の列挙型は単なる定数のリストではなく、メソッドを持つ完全なクラスです!
メソッド name()
定数名を文字列で返します(コードに書かれているとおり):
DayOfWeek day = DayOfWeek.FRIDAY;
System.out.println(day.name()); // "FRIDAY"
メソッド ordinal()
定数の序数(0 始まり)を返します:
System.out.println(DayOfWeek.MONDAY.ordinal()); // 0
System.out.println(DayOfWeek.FRIDAY.ordinal()); // 4
注意: 将来順序が変わる可能性があるなら、ordinal() による保存や比較は避けましょう。名前を使うほうが安全です。
メソッド valueOf(String name)
文字列を対応する enum 値に変換します(そのような定数が存在する場合):
DayOfWeek day = DayOfWeek.valueOf("MONDAY");
System.out.println(day); // MONDAY
一致しない場合は例外 IllegalArgumentException が送出されます。
メソッド values()
enum の全値を配列で返します(上で既出):
DayOfWeek[] days = DayOfWeek.values();
4. フィールド、コンストラクタ、メソッドを持つ enum
Java の列挙型は拡張できます。フィールド、コンストラクタ、メソッドを追加可能です。つまり、単なる名前のリストではなく小さなクラスです。
例: 曜日のローカライズ名付き
public enum DayOfWeek
{
MONDAY("月曜日"),
TUESDAY("火曜日"),
WEDNESDAY("水曜日"),
THURSDAY("木曜日"),
FRIDAY("金曜日"),
SATURDAY("土曜日"),
SUNDAY("日曜日");
private final String russianName;
// コンストラクタ(デフォルトで private)
DayOfWeek(String russianName)
{
this.russianName = russianName;
}
public String getRussianName()
{
return russianName;
}
}
この仕組みの詳細は、レベル 27+ で OOP を学ぶときに取り上げます :P
これで次のように使えます:
DayOfWeek day = DayOfWeek.WEDNESDAY;
System.out.println(day.getRussianName()); // "水曜日"
ポイント: 各 enum の値ごとに独自のデータ(この例では表示名)を持たせられます。
enum を使う利点
- 型安全性: 列挙にない値を誤って代入することができません。
- 可読性: コード自体が説明的になります(TrafficLight.RED を 1 や "red" の代わりに使える)。
- 保守性: 候補を追加・削除したいときは 1 か所を変更すれば済みます。
- switch と相性が良い: enum は値による分岐に最適です。
- 拡張できる: フィールドやメソッドを追加し、インターフェースも実装できます。
- ミスの削減: コンパイラが分岐漏れなどを見つけるのに役立ちます(特に switch 構文)。
6. 実践: アプリに enum を導入する
ミニアプリに enum で曜日のサポートを追加しましょう。
ステップ 1. enum を宣言する
public enum DayOfWeek
{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
ステップ 2. コードで使う
System.out.println("曜日を入力してください(例: MONDAY):");
Scanner console = new Scanner(System.in);
String input = console.nextLine().toUpperCase();
DayOfWeek day = DayOfWeek.valueOf(input);
switch (day)
{
case MONDAY:
System.out.println("仕事の週の始まり!");
break;
case FRIDAY:
System.out.println("もうすぐ週末!");
break;
case SATURDAY:
case SUNDAY:
System.out.println("やった、週末だ!");
break;
default:
System.out.println("普通の平日。");
}
ここで起きていること:
- ユーザーが曜日を入力します(例えば "monday" や "MONDAY")。
- 大文字小文字に依存しないように、toUpperCase() で大文字にします。
- valueOf で文字列を enum 値に変換します。
- switch で出力メッセージを分岐します。
- 不正な入力なら例外を捕捉して警告を出します。
7. enum でよくある間違い
よくある間違い1: enum の代わりに文字列や数値を使う。 初心者がよく次のように書いてしまいます:
int day = 1; // 1 は月曜日?
または
String status = "DELIVERED";
これはよくありません。つづりミスの危険があり、保守も難しくなります。enum を使いましょう!
よくある間違い2: == と .equals() での比較。 Java では enum の値は == で比較してかまいません。各定数は enum クラス内で一意だからです:
if (day == DayOfWeek.MONDAY) { ... } // OK!
.equals() でも動作しますが、一般には == が使われます。
よくある間違い3: 要素の命名が悪い。 要素を VALUE1、VALUE2、VALUE3 のように名付けないでください。1 か月後には誰も意味を理解できません。意味のある名前を使いましょう。
よくある間違い4: ロジックで ordinal() を使う。 次のように書くのはやめましょう:
if (day.ordinal() == 0) { ... } // やめましょう!
要素の並び順は変更される可能性があり、その場合すべてが壊れてしまいます。名前で判断しましょう!
GO TO FULL VERSION