Enum

Java

自作Enumの本質

MyEnum extends java.lang.Enum {

public static final A,

public static final B;

}

継承したメソッド

1.ordinal() 順番

2.compareTo()

Color.RED.compareTo(Color.BLUE); 順番差

3.values()

for(Season s : Season.values())

4.toString() System.out.println(Season.Spring) //Spring

5.valueOf() System.out.println(Season.valueOf("Spring")) //Season.Spring

if(Season.contains("aaa")){

Season s = Season.valueOf("aaa");

}

6.equals() 参照比較

7. name()

サンプル1

public enum Season {

Spring("春"), Summer("夏"), Autummn("秋"), Winter("冬");

private final String desc;

private Season(String desc){

this.desc = desc;

}

public String desc(){

return desc;

}

public static Season getBestSeason(){

return Spring;

}

//★内部判断

public static boolean contains(String name){

for (Season s : Season.values()) {

if(s.name().equals(name)){

return true;

}

}

return false;

}

@Override

public String toString() {

return name() + "(" + desc() + ")"

}

}

// staticメソッドを呼び出す

Season.getBestSeason();

// 非staticメソッドを呼び出す

Season.Spring.desc();

//★外部判断

public static <T extends Enum<T>> boolean Contain(Class<T> c, String name){

for (T t : c.getEnumConstants()) {

if(t.name().equals(name)){

return true;

}

}

return false;

}

サンプル2

public enum Role {

Admin("管理者", new LifeTime(), new Scope()),

User("一般ユーザ", new LifeTime(), new Scope());

private String name;

private LifeTime lifeTime;

private Scope scope;

private Role(String name, LifeTime lifeTime, Scope scope) {

this.name = name;

this.lifeTime = lifeTime;

this.scope = scope;

}

// getter

}

サンプル3

public enum WeekDay{

SUN(0), MON(), TUE, WEN, THI, FRI, SAT; // 必ず先頭

private WeekDay(){ // privateのみ

System.out.println("WeekDay()");

}

private WeekDay(int day){

System.out.println(day);

}

}

public enum TrafficLamp{

RED(10){

@Override

public TrafficLamp nextLamp() {

return GREEN;

}

},

GREEN(20){

@Override

public TrafficLamp nextLamp() {

return YELLOW;

}

},

YELLOW(30){

@Override

public TrafficLamp nextLamp() {

return RED;

}

};

public abstract TrafficLamp nextLamp();

public int time;

private TrafficLamp(int time){

this.time = time;

}

}

// 利用側

WeekDay weekDay = WeekDay.SUN;

System.out.println(weekDay); // SUN

System.out.println(weekDay.name()); // SUN

System.out.println(weekDay.ordinal()); // 0

System.out.println(weekDay.toString()); // SUN

System.out.println(WeekDay.valueOf("MON")); // MON

System.out.println(WeekDay.values().length); // 7

for (WeekDay wd : WeekDay.values()) {

System.out.println(wd);

}

TrafficLamp lamp = TrafficLamp.GREEN;

System.out.println(lamp.time); // 20

System.out.println(lamp.nextLamp()); // YELLOW

サンプル4(インターフェース)

public interface Behaviour {

void print();

}

public enum Color implements Behaviour {

RED("赤", 1), GREEN("緑", 2), WHITE("白", 3);

private String name;

private int index;

private Color(String name, int index) {

this.name = name;

this.index = index;

}

public static String getName(int index) {

for (Color c : Color.values()) {

if (c.getIndex() == index) {

return c.name;

}

}

return null;

}

// getter setter

@Override

public void print() {

System.out.println(this.index + ":" + this.name);

}

}

public interface Food {

enum Coffee implements Food{

BLACK, DECAF, LATTE, CAPPUCCINO

}

enum Dessert implements Food{

FRUIT, CAKE

}

}

JavaのEnumの注意点について

★swtich文

public static void method(Season season){

if(season == null){

// do something

}

switch(season){ ←seasonがnullの場合、NullPointerException発生

case Spring:

// do something

break;

...

default: ←Enumの内容が変わると、caseの変更も忘れないよう

throw new AssertionError("Enum Error");

break;

}

}

★valueOfメソッド

ListのindexOfメソッドは見つからない場合に-1を返す

EnumのvalueOfメソッドは見つからない場合に例外発生

解決方法1

try{

Season s = Season.valueOf(name);

}catch(IllegalArgumentException){

System.out.println("該当なし");

}

解決方法2

valueOfメソッドを呼ぶ前に、左記の自作containsメソッドでまず判断

★Enumの項目数

enum Const{

A1, A2, ... A64;

}

enum LargeConst{

A1, A2, ... A64, A65;

}

EnumSet<Const> cs = EnumSet.allOf(Const.class);

EnumSet<LargeConst> lcs = EnumSet.allOf(LargeConst.class);

System.out.println(cs.getClass()); // java.util.RegularEnumSet

System.out.println(lcs.getClass()); // java.util.JumboEnumSet

※できるだけ、Enumの項目数は64以下に収めよう

Enum式のFactory Pattern

interface Car{

}

class FordCar implements Car{

}

class BuickCar implements Car{

}

//★一般のFactory Pattern

public class Factory{

public static Car createCar(Class<? extends Car> c){

try{

return (Car)c.newInstance();

}catch(Exception e){

e.printStackTrace();

}

return null;

}

}

//使用例

Car car = CarFactory.createCar(FordCar.class);

//★Enum式のFactory Pattern1(非staticメソッド)

public enum CarFactory {

FordCar, BuickCar;

public Car create(){

switch (this) {

case FordCar:

return new FordCar();

case BuickCar:

return new BuickCar();

default:

throw new AssertionError("Error");

}

}

}

//使用例

Car car = CarFactory.FordCar.create();

//★Enum式のFactory Pattern2(抽象方法)

public enum CarFactory {

FordCar{

@Override

public Car create() {

return new FordCar();

}

},

BuickCar{

@Override

public Car create() {

return new BuickCar();

}

};

public abstract Car create();

}

//使用例

Car car = CarFactory.FordCar.create();

Enum式のFactory Patternのメリット

・間違いにくい

一般式はCar car = CarFactory.createCar(Car.class); ×

・効率よい(int型の計算)

・Decoupling

利用側はFordCar.classなどを意識しなくてもよい

C#

★Flagsの用法

enum Single : short

{

Black = 0,

Red = 1,

Green = 2,

Blue = 4

};

[Flags]

enum Multi : short

{

Black = 0,

Red = 1,

Green = 2,

Blue = 4

};

for(int val = 0; val <= 8; val++)

{

Console.WriteLine("{0,3} - {1}", val, ( (Single)val ).ToString());

}

出力:

0 - Black

1 - Red

2 - Green

3 -

4 - Blue

5 -

6 -

7 -

8 -

for(int val = 0; val <= 8; val++)

{

Console.WriteLine ("{0,3} - {1}", val, ( (Multi)val ).ToString());

}

出力:

0 - Black

1 - Red

2 - Green

3 - Red, Green

4 - Blue

5 - Red, Blue

6 - Green, Blue

7 - Red, Green, Blue

8 -

★EnumSetとEnumMap(Java)

java.util.EnumSet 重複なし

public class Text {

public enum Style { BOLD, ITALIC, ...}

public void applyStyles(Set<Style> styles) { ... }

}

text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

java.util.EnumMap keyはenum型

サンプル1

public class Herb {

public enum Type {A, B, C...};

private final String name;

private final Type type;

Herb(String name, Type type) {

this.name = name;

this.type = type;

}

@Override

public String toString() {

return name;

}

}

Herb[] garden = ...;

Map<Herb.Type, Set<Herb>> herbsByType =

new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);

for (Herb.Type t : Herb.Type.values()) {

herbsByType.put(t, new HashSet<Herb>());

}

for (Herb h : garden) {

herbsByType.get(h.type).add(h);

}

サンプル2

public enum Phase {

SOLID, LIQUID, GAS;

public enum Transition {

MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),

BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),

SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);

private final Phase src;

private final Phase dst;

Transition(Phase src, Phase dst) {

this.src = src;

this.dst = dst;

}

private static final Map<Phase, Map<Phase, Transition>> m =

new EnumMap<Phase, Map<Phase, Transition>>(Phase.class);

static {

for (Phase p : Phase.values()) {

m.put(p, new EnumMap<Phase, Transition>(Phase.class));

}

for (Transition trans : Transition.values()) {

m.get(trans.src).put(trans.dst, trans);

}

}

public static Transition from(Phase src, Phase dst) {

return m.get(src).get(dst);

}

}

}

★Extend enum functionality

Mirror

enum DrawableColor {

red { @Override public void draw() { } },

green { @Override public void draw() { } },

blue { @Override public void draw() { } },

;

public abstract void draw();

}

Color color = ...

DrawableColor.valueOf(color.name()).draw();

EnumMap

Map<Color, Supplier<Void>> drawers = new EnumMap<>(Color.class) {{

put(red, new Supplier<Void>() { @Override public void get();});

put(green, new Supplier<Void>() { @Override public void get();})

put(blue, new Supplier<Void>() { @Override public void get();})

}}

drawers.get(color).get();