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();