列挙型（enum）の基本的な使い方とコード例

#はじめに
enum は列挙型と呼ばれ、いくつかの定数をひとまとめにすることができる優れものらしい。
せっかく勉強したので記事作成の練習ついでに個人用としてまとめておく。
「あれ、これってどう使うんだっけ？」と思ったときにチラッと見て確認できる記事を目標とした。
なお、本記事では基本的な列挙型の使い方のみを扱うため、内部の処理等については言及しない。

#列挙型の特徴
- 複数の定数（列挙子）を一つの型で統一して管理できる
- 一つの列挙子に複数の表現が定義できる
- 列挙子に共通の処理を定義することができる

要は定数をまとめて管理できるということだ。
ただし、定数に変更があるたびにコード書き換えが必要になる。
実装する前に本当に列挙型で定義するべきかどうか検討しよう。

#列挙型の定義
本項では列挙型の定義について紹介する。
ごく簡単なコード例は以下の通りだ。
###コード例

```java

public enum Fruit {		//"class" ⇒ "enum" に書き換える
	//列挙子の定義
	APPLE,
	ORANGE,
	PEACH;
}
```

```java

public class Basket {
	public static void main(String[] args) {

		Fruit flt = Fruit.ORANGE;				//enumを取得
		System.out.println( flt.toString() );	//ORANGE
	}
}
```


設定した定数（列挙子）のいずれかを持つ enum を変数として保持し、必要に応じて取得できる。
上記の例では`APPLE, ORANGE, PEACH`を定数として入力したため、他の文字列（`GRAPE`等）が出力される心配はない。
このように、事前に定義した定数のみを扱えることが enum の特徴でありメリットだ。


列挙子は複数のプリミティブ型やクラス型を組み合わせて定義することもできる。以下はその例だ。
###コード例

```java
public enum Fruit {

	APPLE("りんご", 1),
	ORANGE("オレンジ", 2),
	PEACH("もも", 3);
	
	private String label;
	private int id;


	private Fruit(String label, int id) {	//コンストラクタはprivateで宣言
		this.label = label;
		this.id = id;
	}


	public String getLabel() {
		return label;
	}

	public int getId() {
		return id;
	}
}
```

```java

public class Basket {

	public static void main(String[] args) {

		Fruit flt = Fruit.APPLE;
		System.out.println( flt.getLabel() );		//りんご

		System.out.println( Fruit.PEACH.getId() );	//3
	}
}
```

上記の例では列挙子に文字列と整数を組み合わせている。
`Fruit`クラスと`Basket`クラスを見比べれば、対応した値をそれぞれ取得できていることがわかるはずだ。

なお、列挙子を組み合わせで定義して運用するには、フィールド、コンストラクタ、メソッドをそれぞれ定義する必要がある。
逆に言えば、必要に応じてフィールドやコンストラクタ、メソッドを定義することができるということだ。

簡単なメソッドを定義した例を以下に示す。
###コード例

```java
public enum Fruit {

	APPLE("りんご", 1),
	ORANGE("オレンジ", 2),
	PEACH("もも", 3);

	private String label;
	private int id;


	private Fruit(String label, int id) {
		this.label = label;
		this.id = id;
	}


	public String getLabel() {
		return label;
	}

	public int getId() {
		return id;
	}


	public static Fruit getById(int id) {

		for( Fruit flt : Fruit.values() ) {	//拡張for文による走査
			if( flt.getId() == id ) {
				return flt;					//条件に一致するインスタンスを返す
			}
		}
		return null;
	}
}
```

```java

public class Basket {

	public static void main(String[] args) {

		Fruit flt = Fruit.getById(2);
		System.out.println( flt.getLabel() );	//オレンジ
	}
}
```


メソッドによっては必ずしも enum クラス内で定義する必要はないが（例えば上記例の`getById`メソッドは別のクラスで定義しても問題なく運用できる）、列挙子まわりの汎用的なメソッドをまとめておくと便利だろう。

#列挙型のメソッド
列挙型には有用なメソッドが最初から用意されている。
前項のコード例にも記載してあるが、本項では改めて紹介しよう。

###・toString()

```java

public class Basket {
	public static void main(String[] args) {

		Fruit flt = Fruit.ORANGE;
		System.out.println( flt.toString() );	//ORANGE
	}
}
```

`toString()`は列挙子として宣言した文字列を取得するメソッドだ。
`name()`も同じ結果を得られるが、こちらは非推奨とされているようだ。
なお、`toString()`はオーバーライド可能だが、`name()`は不可という違いがある。

###・valueOf(String name)

```java

public class Basket {

	public static void main(String[] args) {

		Fruit flt = Fruit.valueOf("PEACH");
		System.out.println( flt.getLabel() );	//もも
	}
}
```

`valueOf(String name)`は引数の文字列に合致する列挙子を返すメソッドだ。
一致する列挙子が存在しない場合は`IllegalArgumentException`を返すので注意しよう。

###・values()

```java

public class Basket {

	public static void main(String[] args) {

		for( Fruit flt : Fruit.values() ) {
			System.out.println( flt.getLabel() );	//りんご
													//オレンジ
													//もも
		}
	}
}
```

`values()`は主に拡張for文で使われるメソッドだ。
上記例の通り、列挙子を網羅的に処理することができる。


#終わりに
今回初めてQiita記事を書いたが、やはり知識不足を実感した。
また、不明なところはあちこち資料を見て確認したが、ちゃんと見た場所は記録しておかなければすぐ忘れるということもよくわかった。
今後も個人用まとめとして記事を書いていきたいところ。


#参考資料
[enumについて（Qiita記事）](https://qiita.com/Takmiy/items/5e47d87b5085de1ac37f)
[Enum で振る舞う（Qiita記事）](https://qiita.com/KeithYokoma/items/9681b130ea132cfad64d)