Java
2021.11.15
JavaのEnumとは?5分でわかる列挙型の使い方&便利なメソッドまとめ
2023.11.21

1. JavaのEnumとは?

Javaに限らず、プログラミング言語における「定数」は重要です。

JavaのEnumは「列挙型」と呼ばれており、うまく活用することで複数の定数を効率的に管理できます。クラスのような構文を利用することでより便利に使えます。

①Enumの特徴

たとえば、春夏秋冬の4つを引数とするプログラムを作ろうと考えます。

/**
 * 春夏秋冬に応じて処理を変えるメソッド
 * @param season 季節の数値(1:春、2:夏、3:秋、4:冬)
 */
public void setStatus(int season) {
  if (season == 1) {
    // 春の処理
  } else if (season == 2) {
    // 夏の処理
  } else if (season == 3) {
    // 秋の処理
  } else if (season == 4) {
    // 冬の処理
  } else {
    // その他の処理
  }
}

このとき、引数のseasonは整数型であるため、0以下や5以上の値も考慮する必要があります。
また、一見で引数の意味を理解することは難しいでしょう。

Enumを活用することで、次のように記載できます。

/**
 * 季節のEnum
 */
public enum Season {
    Spring, 
    Summer, 
    Autumn, 
    Winter;
}

/**
 * 春夏秋冬に応じて処理を変えるメソッド
 * @param season 季節
 */
public void setStatus(Season season) {
  if (season == Season.Spring) {
    // 春の処理
  } else if (season == Season.Summer) {
    // 夏の処理
  } else if (season == Season.Autumn) {
    // 秋の処理
  } else {
    // 冬の処理
  }
}

このとき、enumを用いて定義したSeasonを「列挙型」と呼び、その中に定義したSpring〜Winterの4項目を「列挙子」と呼びます。

②Enumを使うメリット

Enumを利用するメリットは主に2つあります。

  1. 引数として渡す内容を限定できる
  2. 名称をつけることで可読性が上がる

たとえば、先ほどの季節を表すSeasonをEnumとして定義することで、引数として渡す内容を限定できるため、列挙子以外の値を考慮する必要がなくなります。

Enumを活用することで、比較する対象が文字で見えるため可読性が上がるだけでなく、テストにおける手間も減らせるのです。



2. Enumの基本的な使い方


ここからは、Enumの基本的な使い方を紹介します。

①定義方法

Enumは、クラスと同様に定義を行います。
今度は、フルーツを定義するEnumを宣言してみましょう。

/** 
 * フルーツ
 */
public enum Fruit {
  Orange, 
  Apple, 
  Cherry;
}

②出力方法

Enumで定義した値はそのまま出力できます。

System.out.println(Fruit.Orange);

上記のコードを実行すると、次のように出力されます。

Orange

 

3. Enumの便利な使い方


基本的な使い方がわかったところで、続いてEnumの便利な利用方法を紹介します。

①switch文での使い方

switch文では、Fruitに列挙した内容を指定してswitchで表せます。

/**
 * フルーツの美味しい食べ方を紹介するメソッド
 * @param fruit 紹介するフルーツ
 */
public static void howToEat(Fruit fruit) {
  switch(fruit) {
    case Orange: 
      System.out.println("ジュースにするとおいしいよ");
      break;
    case Apple:
      System.out.println("アップルパイはいかが?");
      break;
    case Cherry:
      System.out.println("そのままがおいしいよ");
      break;
  }
}

// メインメソッド
public static void main(String[] args) {
  howToEat(Fruit.Orange);
}

このとき、case文の条件には列挙子のみを記述することに注意しましょう。

これを実行すると、引数のOrangeに対応する文字列がコンソールに出力されます。

ジュースにするとおいしいよ

②if文での使い方

switch文と同様に、if文を利用してEnumの比較が可能です。

先ほどのhowToEatメソッドを、if文を利用するように書き換えてみましょう。

/**
 * フルーツの美味しい食べ方を紹介するメソッド
 * @param fruit 紹介するフルーツ
 */
public static void howToEat(Fruit fruit) {
  if (fruit == Fruit.Orange) {
      System.out.println("ジュースにするとおいしいよ");
  } else if (fruit == Fruit.Apple) {
      System.out.println("アップルパイはいかが?");
  } else if (fruit == Fruit.Cherry) {
      System.out.println("そのままがおいしいよ");
  }
}

このように、if文を使うことで変数と比較できます。


その場に応じて使いやすい方法で比較するとよいでしょう。

4. Enum同士の比較方法


Javaの場合、文字列をはじめとするクラスインスタンスの比較にはequals メソッドの利用が推奨されています。

Enumはクラスインスタンスのような振る舞いをしますが、==を使って比較できます。

if (fruit == Fruit.Orange) {
  System.out.println("ジュースにするとおいしいよ");
}

もちろん、Enumはクラスインスタンスと同じ扱いができるためequals()メソッドを使った比較も可能です。

if (fruit.equals(Fruit.Orange)) {
  System.out.println("ジュースにするとおいしいよ");
}

ただし、equalsメソッドを使う場合にはnullを考慮する必要があります。

Fruit fruit = null;

// 変数"fruit"がnullであるため、「NullPointerException」がスローされる
if (fruit.equals(Fruit.Orange)) {
  // オレンジの場合の処理 
}

// この場合、fruitがnullでもエラーにならない
if (fruit == Fruit.Orange) {
  // オレンジの場合の処理 
}

コード量も減り可読性も上がりますので、Enumの比較は==を使うと覚えましょう。

5.Enumの便利なメソッド

Enumを活用する上で、知っておくと便利なメソッドを紹介します。

①toStringメソッドで文字列に変換

EnumのtoStringメソッドを使うことで、その定義名を文字列として取得できます。

System.out.println(Fruit.Orange.toString());
// -> 'Orange'と出力される

②ordinalメソッドで宣言された順番を取得

Enumで列挙した内容の順番を使って比較をしたい場合には、ordinalを使います。

定義したEnumの列挙子が、Enumの中で何番目に定義しているかを取得します。

System.out.println(Fruit.Apple.ordinal());
// -> 1 が出力される

③valueOfメソッドで引数と一致する列挙子を取得

文字列からEnumを取得したい場合には、valueOfメソッドを使います。

Fruit apple = Fruit.valueOf("Apple");

なお、存在しないEnumの値を指定した場合には、IllegalArgumentExceptionが発生します。

Fruit grape = Fruit.valueOf("Grape");
// Grape は定義されていないためエラーになる

ユーザーの入力値からEnumを取得する場合には、このエラーについても考慮するようにしましょう。

④valuesメソッドですべての列挙子を取得

valuesメソッドを使うことで、定義されたすべての情報を取得できます。

// 一覧を取得
Fruit[] values = Fruit.values();
// Fruitの定義でループ
for (Fruit f : values) {
  // 番号と内容を出力
  System.out.println(f.ordinal() +" : "+ f.toString());
}

これを実行すると、次のように出力されます。

0 : Orange
1 : Apple
2 : Cherry

Enumで定義した列挙子を配列として取得できるため、全件で処理したいときには便利に利用できます。



6.Enumクラスの使い方


Enumは、名称をつけるだけでなく内部的に違う値を付与することも可能です。
これにより、名称と別名を持つことができます。

public enum Fruit {
  Orange("オレンジ"),
  Apple("りんご"),
  Cherry("さくらんぼ");
    
  /** Enumの和名 */
  private String japanese;

  /**
   * コンストラクタ
   * @param value 和名
   */
  private Fruit(String value) {
    this.japanese = value;
  }

  /**
   * 和名を取得
   */
  public String getJapanese() {
    return this.japanese;
  }
}

①フィールド変数の定義

まずは、定義した名称以外の情報を格納するフィールド変数を定義します。
定義した和名は、このフィールドに格納されます。

/** Enumの和名 */
  private String japanese;

②コンストラクタの定義

コンストラクタでは、和名を引数として受け取り、先ほど定義したjapaneseに代入します。

/**
 * コンストラクタ
 * @param value 和名
 */
private Fruit(String value) {
  this.japanese = value;
}

このコンストラクタに渡される内容は、定義子の後ろに定義した文字列と一致します。
そのため、Fruit.Orangeであれば「オレンジ」が、Fruit.Appleであれば「りんご」がコンストラクタに渡されます。

③メソッドの定義

フィールド変数で宣言した値を取得するためには、自分でメソッドを定義する必要があります。
通常のクラスメソッドと同様にメソッドを定義することで、定義したフィールド変数を自由に利用できます。

/**
   * 和名を取得
   */
  public int getJapanese() {
    return this.japanese;
  }

このgetJapaneseメソッドは外部から利用できるため、次のようなコードを作成できます。


// メッセージを作成
String message = Fruit.Apple + "の和名は"
    + Fruit.Apple.getJapanese() + "です。";

System.out.println(message); 
// -> 'Appleの和名はりんごです。'が出力される



7.Enumを使う際の注意点


Enumはうまく使うことで便利な反面、注意すべき点もあります。
以下の注意点をおさえた上で活用しましょう。

①不適切な管理によりかえってメンテナンス性が悪くなることも

Enumは、列挙する定数をひとまとめにすることを目的として利用します。しかし、数が多くなりすぎたり、似たようなEnumを複数定義したりすると、メンテナンス性がかえって低下するので注意しましょう。

たとえば、野菜と果物をEnumとして定義しています。
このとき、スイカを誤って両方に定義してしまった場合、野菜のスイカと果物のスイカはプログラム上別物として扱われます。

Enumの効果を最大限に活かすためには、追加する項目を精査し、適切に管理することが重要です。

②Enumは新しいインスタンスを生成できない

Enumはクラス構文を用いて記載しますが、通常のクラスとは異なりインスタンスを生成できません。

もし、Enumのインスタンスが生成できると、Fruitに新しい項目を追加できてしまいます。
列挙子として定義した項目以外のインスタンス生成を防止することで、Enumの一貫性を保証しているのです。

ただし、次のようにEnum型の変数定義は可能であり、クラス変数としての利用はできます。

/**
 * Enum型の Fruitをクラス変数にもつクラス
 */
public class Sweets {
    
  private Fruit fruit;
    
  public Fruit getFruit() {
    return this.fruit;
  }

  public Sweets(Fruit fruit) {
    this.fruit = fruit;
  }
}
public static void main(String[] args) {
  // クラスインスタンスの生成  
  final Sweets sweet = new Sweets(Fruit.Cherry);
  
  System.out.println(sweet.getFruit());
  // -> 'Cherry' が表示される
}




この記事をシェア