Java で文字列や値から Enum 定数を逆引きする

## 概要

- Java で値から Enum 定数を取得するサンプルコード
- サンプルコードは javac コマンドでビルドして java コマンドで実行する
- 動作確認環境: macOS Catalina + Java 8 (AdoptOpenJDK 1.8.0_242-b08)

## Enum は Java 5 (コードネーム Tiger) から使用できる

[列挙型](https://docs.oracle.com/javase/jp/1.5.0/guide/language/enums.html)

> Tiger では、Java™ プログラミング言語で列挙された型を言語的にサポートしました。列挙のもっとも簡単な形式では、C、C++、および C# の形式に似ています。

## サンプルコード

```java
package com.example.enums;

/** シンプルな列挙型を定義 */
public enum MetaName {
  FOO, BAR, BAZ;
}
```

```java
package com.example.enums;

/** 値を1つ持つ列挙型を定義 */
public enum OneValueEnum {

  ONE(1), TWO(2), THREE(3);

  private final int number;

  /**
   * 値を指定して enum 定数を生成。
   */
  OneValueEnum(int number) {
    this.number = number;
  }

  /**
   * 値を返すメソッドを用意。
   */
  public int getNumber() {
    return number;
  }

  /**
   * 値に合致する enum 定数を返す。
   */
  public static OneValueEnum getByNumber(int number) {
    // 値から enum 定数を特定して返す処理
    for (OneValueEnum value : OneValueEnum.values()) {
      if (value.getNumber() == number) {
        return value;
      }
    }
    return null; // 特定できない場合
  }
}
```

```java
package com.example;

import com.example.enums.MetaName;
import com.example.enums.OneValueEnum;

public class Main {

  public static void main(String[] args) {
    testMetaName();
    testOneValueEnum();
  }

  private static void testMetaName() {
    try {
      // 自動生成される valueOf メソッドを使うと、文字列から Enum 定数を取得できる
      System.out.println("***** FOO *****");
      MetaName foo = MetaName.valueOf("FOO");
      System.out.println("foo.getClass=" + foo.getClass());
      System.out.println("foo.getDeclaringClass=" + foo.getDeclaringClass());
      System.out.println("foo.toString=" + foo.toString());

      // 存在しない定数を取得しようとすると IllegalArgumentException が発生する
      System.out.println("***** bar *****");
      MetaName bar = MetaName.valueOf("bar");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private static void testOneValueEnum() {
    try {
      // 自動生成される valueOf メソッドを使うと、文字列から Enum 定数を取得できる
      System.out.println("***** ONE *****");
      OneValueEnum one = OneValueEnum.valueOf("ONE");
      System.out.println("one.getClass=" + one.getClass());
      System.out.println("one.getDeclaringClass=" + one.getDeclaringClass());
      System.out.println("one.toString=" + one.toString());
      System.out.println("one.getNumber=" + one.getNumber());

      // 値に合致する Enum 定数を取得するためには、自前実装が必要
      System.out.println("***** 1 *****");
      OneValueEnum ichi = OneValueEnum.getByNumber(1); // 自前実装メソッドをコール
      System.out.println("ichi.getClass=" + ichi.getClass());
      System.out.println("ichi.getDeclaringClass=" + ichi.getDeclaringClass());
      System.out.println("ichi.toString=" + ichi.toString());
      System.out.println("ichi.getNumber=" + ichi.getNumber());

      // 値に合致する Enum 定数が無かったので null を返すようにしている
      // (自前実装なので任意の処理をすれば良い)
      System.out.println("***** 9 *****");
      OneValueEnum kyu = OneValueEnum.getByNumber(9);
      System.out.println("kyu=" + kyu);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
```

## サンプルコードのビルド

ソースコードを配置。

```
$ tree
.
└── src
    └── com
        └── example
            ├── Main.java
            └── enums
                ├── MetaName.java
                └── OneValueEnum.java
```

クラスファイル出力先のディレクトリを作成。

```
$ mkdir dest
```

javac コマンドでコンパイル。

```
$ javac -sourcepath src src/com/example/Main.java -d dest
```

クラスファイルが生成されているのを確認。

```
$ tree
.
├── dest
│   └── com
│       └── example
│           ├── Main.class
│           └── enums
│               ├── MetaName.class
│               └── OneValueEnum.class
└── src
    └── com
        └── example
            ├── Main.java
            └── enums
                ├── MetaName.java
                └── OneValueEnum.java
```

## サンプルの実行結果

```
$ java -classpath dest com.example.Main
***** FOO *****
foo.getClass=class com.example.enums.MetaName
foo.getDeclaringClass=class com.example.enums.MetaName
foo.toString=FOO
***** bar *****
java.lang.IllegalArgumentException: No enum constant com.example.enums.MetaName.bar
	at java.lang.Enum.valueOf(Enum.java:238)
	at com.example.enums.MetaName.valueOf(MetaName.java:3)
	at com.example.Main.testMetaName(Main.java:23)
	at com.example.Main.main(Main.java:9)
***** ONE *****
one.getClass=class com.example.enums.OneValueEnum
one.getDeclaringClass=class com.example.enums.OneValueEnum
one.toString=ONE
one.getNumber=1
***** 1 *****
ichi.getClass=class com.example.enums.OneValueEnum
ichi.getDeclaringClass=class com.example.enums.OneValueEnum
ichi.toString=ONE
ichi.getNumber=1
***** 9 *****
kyu=null
```

## 参考資料

- [JDK 5.0 ドキュメント \- 列挙型](https://docs.oracle.com/javase/jp/1.5.0/guide/language/enums.html)
- [Enum \(Java Platform SE 8 \)](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Enum.html)
- [OpenJDK 8 の java コマンドと javac コマンドのヘルプ \- Qiita](https://qiita.com/niwasawa/items/62c3749b8d4fbe91b899)