【Java】列挙型

* 値そのものに意味がなく、シンボルとして意味を持つ定数で`final static`を使わない
    * `public final static int SPRING = 0;`はint型なので全数値も受け取れる
    * 季節を数値で表して月を数値で表してると引数など取り違える可能性
* →***列挙型**を使う
* `enum　型名`で名前をカンマ区切り
* 引数はintではなく**enumで定義した名前の型！**

```java
//Season型のSPRINGにアクセスする場合、Season.SPRING
public enum Season {
  SPRING,
  SUMMER,
  AUTUMN,
  WINTER,
}
```
```java
public class EnumConstClient {

  public static void main(String[] args) {
    var ecs = new EnumConstSeason();
    ecs.processSeason(EnumConstSeason.SPRING);
    ecs.processSeason(4);
    ecs.processSeason(EnumConstMonth.JANUARY);
  }
}

```java
public class EnumSeason {
  public void processSeason(Season season) {
    System.out.println(season);
  }

  public static void main(String[] args) {
    var es = new EnumSeason();
    es.processSeason(Season.SPRING);
    //Season型で定義されてない定数はエラー
    // es.processSeason(4); //コンパイルエラー
    // es.processSeason(EnumConstMonth.JANUARY);　//コンパイルエラー
  }
}
``

#列挙型のメンバー
* **name()**：列挙定数の名前取得
* **ordinal()**：列挙定数の順序取得
* **toString()**：列挙定数の名前取得、個々の型で適切な文字列表現に置き換えられている可能性
* **values()**：全ての列挙定数取得
* **valueOf(String name)**：名前から列挙定数取得

```java
public class EnumMethod {
  public static void main(String[] args) {
    for (var se : Season.values()) {
      //インデックス番号:名前で出力q
      System.out.println(se.ordinal() + ":" + se.toString());
    }
    //文字列から列挙型取得
    var s = Season.valueOf("SPRING");
    System.out.println(s instanceof Season); //true
  }
}
```

#メンバーの定義
* フィールド定義：列挙型にそれ自体の名前とは別に画面に表示する/DBに保存するといった特定の意味を持った値をもたせたい場合
* コンストラクタ定義
    * アクセス修飾子はprivate
        * 列挙型では**new演算子でインスタンスを生成できない**
        * Season.SPRINGのように列挙定数の参照が暗黙的にオブジェクト生成する
        * 自前コンストラクタ定義の際にはアクセス修飾子はprivate
    * コンストラクタ内でsuper呼べない
    * 同じ型の非定数staticフィールドのアクセス不可
* 列挙定数の末尾は定数とメンバーの区切りに`;`必要

```java
//列挙定数でコンストラクタ呼びだし
public enum Season {
    SPRING(0, "春"),
    SUMMER(1, "夏"),
    AUTUMN(2, "秋"),
    WINTER(4, "冬");

  //フィールド宣言
  private int code; //季節コード
  private String jpName; //表示名
  //コンストラクタ
  private Season(int code, String jpName) {
    this.code = code;
    this.jpName = jpName;
  }
  //メソッド
  public int toSeasonValue() {
    return this.code;
  }
  //ゲッター用意
  @Override
  public String toString() {
    return this.jpName;
  }

  //public abstract void show();
}
```

```java
public class EnumBasic {
  public static void main(String[] args) {
    System.out.println(Season.SPRING); //春
    System.out.println(Season.SPRING.toString());　//春
    System.out.println(Season.SPRING.toSeasonValue()); //0
  }
}
```

##個々の列挙定数に独自の実装をする
* 個々の列挙定数で実装すべき機能を抽象メソッドで準備
* 列挙定数ブロックで抽象メソッドをOverride


```java
public enum Season {
  //列挙定数
  SPRING(0, "春") {
    @Override
    public void show() {
      System.out.println("春はあけぼの");
    }
  },
  SUMMER(1, "夏") {
    @Override
    public void show() {
      System.out.println("夏は夜");
    }
  },
  AUTUMN(2, "秋") {
    @Override
    public void show() {
      System.out.println("秋は夕暮れ");
    }
  },
  WINTER(4, "冬") {
    @Override
    public void show() {
      System.out.println("冬はつとめて");
    }
  };
  //フィールド宣言
  private int code; //季節コード
  private String jpName; //表示名
  //コンストラクタ
  private Season(int code, String jpName) {
    this.code = code;
    this.jpName = jpName;
  }
  //メソッド
  public int toSeasonValue() {
    return this.code;
  }

  @Override
  public String toString() {
    return this.jpName;
  }
  //列挙定数が実装すべき機能（抽象メソッド）
  public abstract void show();
}
```

```java
public class EnumMethod {
  public static void main(String[] args) {
    for (var se: Season.values()) {
      se.show(); //春はあけぼの 夏は夜 秋は夕暮れ 冬はつとめて"
    }
  }
}
```

#ビットフィールド
* 複数のフラグをビット並びで表現すること
* ビット論理和演算子でまとめる

```java
//大文字小文字区別しない、マルチラインモード有効
var ptn = Pattern.compile("^[a-z0-9._-]*",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);`
```

* **オンオフ検査**に有効
    * &ビット論理演算子で該当ビットがオン（1）でないと全ビットがオフ（0）になる
    
```java
import java.util.regex.Pattern;

public class EnumBit {
  public static void main(String[] args) {
    var flags = Pattern.CASE_INSENSITIVE | Pattern.MULTILINE;
    if ((flags & Pattern.COMMENTS) != 0) {
      System.out.println("COMMENTSは有効です。");
    }
  }
}
``` 

* EnumSetと組み合わせて可読性をあげる

```java
//列挙型定義
public enum PatternFlag {
  UNIX_LINES,
  CASE_INSENSITIVE,
  COMMENTS,
  MULTILINE,
}
``` 
```java
//列挙型を受けとる
Pattern.compile("^[a-z0-9._-]*",
EnumSet.of(PatternFlag.CASE_INSENSITIVE, PatternFlag.MULTILINE));
```