JavaのEnum型を使って分かりやすいプログラムを書く方法

プログラミング

プログラムはできるだけシンプルに分かりやすく記述することで、バグや認識違いを少なくすることができます。

JavaのEnum型は、型に安全なプログラムにすることができる仕組みで、その結果プログラムが分かりやすくなり認識違いを少なくできる手法の1つです。

本記事では、JavaのEnum型を使って分かりやすいプログラムを書く方法について解説します。

記事内に記載しているプログラムは、Java11を使って動作確認をしています。

JavaのEnum型

JavaのEnum型について、以下の内容を解説します。

  • Enum型とは
  • Enum型の基本
  • Enum型を使った操作
  • Enum型が持つメソッド
  • Enum型に独自メソッドを追加する方法
  • EnumSet型
  • EnumMap型

Enum型とは

Enum型とは日本語で列挙型とも呼ばれ、定数をグループとしてひとまとまりにして、クラスとして表したものです。
数が限定されている定数として、季節や曜日などがありますが、これらをまとめて列挙したEnumとすることで以下のメリットが得られます。

  • nullや全く関係ない定数を意識することがなくなり、型に安全なプログラムにすることができる。
  • まとまりに意味のある名前を付けることで、プログラムが分かりやすくなる。

Enum型の基本

Enum型を定義する基本となるプログラムは以下の通りです。

public enum Season {SPRING, SUMMER, AUTUMN, WINTER};

上記のプログラムでは、定数となる4つの季節をSeasonというEnum型にまとめています。
Enumはクラスの1つですが、newすることができないのが特徴です。

Enumクラスを利用する際には、以下のようにします。

Season spring = Season.SPRING;
System.out.println(spring); // -> SPRING

Season型のEnumクラスの変数に直接Enumのメンバを代入することができます。
出力すると、定義したメンバ名がそのまま出力されます。

Enum型を使った操作

Enum型の主な操作として、代入、比較、switch文の操作があります。

代入

Enum型は前述の通り、直接変数に代入することができます。
また、通常のクラスと同様に、同じEnum型の変数であれば、入れ替えたり、再度代入したりすることができます。

Season autumn = Season.AUTUMN;
Season fall = autumn;
System.out.println(fall); // -> AUTUMN

比較

Enum型同士の比較は、イコールで行うことができます。

Season winter = Season.WINTER;
if (winter == Season.WINTER) {
    System.out.println(winter);
} else {
    System.out.println("not WINTER");
}

また、compareToによる比較をすることも可能です。

if (winter.compareTo(Season.WINTER) == 0) {
    System.out.println(winter);
} else {
    System.out.println("not WINTER");
}

switch文

Enum型が一番力を発揮するのが、switchによる分岐です。

Season summer = Season.SUMMER;
switch(summer) {
    case SPRING:
        System.out.println("Spring");
        break;
    case SUMMER:
        System.out.println("Summer");
        break;
    case AUTUMN:
        System.out.println("Autumn");
        break;
    case WINTER:
        System.out.println("Winter");
        break;
}

Enum型では、分岐の対象となるメンバの数が限定されており、それ以外に取りうる値(型)がないので、default文に入ることはありません。(不要のため通常記述することもありません)
このように型を限定させることで、見た目にも分かりやすく、安全なプログラムを作ることが出来ます。

Enum型が持つメソッド

Enumクラスにもいくつかのメソッドが提供されています。

Enumクラスのメンバで使うことが出来る主なメソッドが、name、ordinal、toStringです。

Season season = Season.SPRING;
System.out.println(season.name()); // -> SPRING
System.out.println(season.ordinal()); // -> 0
System.out.println(season.toString()); // -> SPRING

nameとtoStringは通常同じ結果で、メンバの定義名を返します。
ordinalは列挙しているメンバの順番(スタートは0)を返します。

Enumクラス自身で使うことが出来る主なメソッドが、valueOfとvaluesです。

System.out.println(Season.valueOf("SPRING")); // -> SPRING
System.out.println(Season.valueOf("spring")); // -> java.lang.IllegalArgumentException
for (Season s : Season.values()) {
    System.out.println(s); // -> SPRING -> SUMMER -> AUTUMN -> WINTER
}

valueOfは引数で指定したメンバのインスタンスを作成します。
存在しないメンバ名を指定すると例外が発生します。

valuesは定義している全メンバを配列で返します。

Enum型に独自メソッドを追加する方法

Enumクラスにもコンストラクタや独自メソッドを追加することができます。
例えば、以下のように3つのタイプを持つ定数をメンバとして、それぞれを数値と関連させたEnumを作成できます。

public enum SpeedType {
    SLOW(1),
    NATUAL(2),
    FAST(3);

    private int type;

    private SpeedType(int type) {
        this.type = type;
    }

    public int getSpeedType() {
        return this.type;
    }
}

上記のEnumクラスを使うプログラムが以下となります。

SpeedType speed = SpeedType.SLOW;
System.out.println(speed); // -> SLOW
System.out.println(speed.getSpeedType()); // -> 1

実際の開発現場では、このようなタイプをデータベースでは数値で管理し、プログラム上では意味を持つ名前に関連させて扱います。
Enumクラスとして扱うことで、外部で使用している同じ意味を持つ数値や文字列との相互変換が簡単で、統一されたプログラムにすることができます。

EnumSet型

Enumクラスの他にもEnumSetクラスが提供されています。
EnumSetは、要素にEnumのメンバを持つ集合です。

EnumSetクラスの変数は、通常のSetと同様にaddやcontains、removeなどのメソッドを持ちます。
ここでは、EnumSet自身が持つメソッド(staticメソッド)を紹介します。

allOfは、Enum型から全メンバを要素として持つEnumSetを作成します。

EnumSet seasons = EnumSet.allOf(Season.class);
System.out.println(seasons.size()); // -> 4
seasons.forEach(System.out::println); // -> SPRING -> SUMMER -> AUTUMN -> WINTER

noneOfは、要素数が0のEnumSetを作成します。

EnumSet none = EnumSet.noneOf(Season.class);
System.out.println(none.size()); // -> 0
none.forEach(System.out::println);

ofは、指定したEnumメンバを持つEnumSetを作成します。

EnumSet springs = EnumSet.of(Season.SPRING);
System.out.println(springs.size()); // -> 1
springs.forEach(System.out::println); // -> SPRING

rangeは、Enumの定義された順番で、範囲内のメンバを持つEnumSetを作成します。

EnumSet springToAutumn = EnumSet.range(Season.SPRING, Season.AUTUMN);
System.out.println(springToAutumn.size()); // -> 3
springToAutumn.forEach(System.out::println); // -> SPRING -> SUMMER -> AUTUMN

EnumMap型

EnumMapは、キーがEnum型となるMapです。
こちらも操作は通常のMapと同じとなります。

EnumMap<Season, String> seasonMap = new EnumMap<>(Season.class);
seasonMap.put(Season.SPRING, "春");
seasonMap.put(Season.SUMMER, "夏");
seasonMap.put(Season.AUTUMN, "秋");
seasonMap.forEach((k, v) -> System.out.println(k + " : " + v));
  // -> SPRING : 春 -> SUMMER : 夏 -> AUTUMN : 秋
System.out.println(seasonMap.containsKey(Season.WINTER)); // -> false

まとめ

JavaのEnum型をまとめると以下となります。

  • Enum型は列挙型とも呼ばれ、定数をグループ化して意味のあるクラスとして表したものである。
  • Enumを利用することで、型に安全で、分かりやすいプログラムにすることができる。
  • Enum型の他に、EnumSetやEnumMapがある。

定数を意味のあるまとまりとして扱いたい場合には非常に有用となりますので、ぜひ活用してみてください。

 

今回は、JavaのEnum型について解説しました。

以上、参考になれば幸いです。

コメント

タイトルとURLをコピーしました