2013年4月30日火曜日

Enumノススメ

ふとしたチャンスで借りて読んだ EffectiveJava. ずっとEnumの使い方を勘違いしていたので矯正を兼ねて
メモメモφ(・ω・ )

Enumノススメ

なんという今更感.
だが, それがいい.

1. Enumって?

日本語に直すと 列挙型. 要するに関連する定数をまとめたもの. もともとは基本的に int値らしい. あらかじめ要素数がわかっている際に効果を発揮し, 別の要素が混ざらなくなる.

たとえば実際 EffectiveJavaにある例から. 
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
リンゴ, オレンジの種類を定数にしておきたいとする. なにが困るかというと, たとえば品種改良を表すメソッド
public void breed(int variety1, int variety2){}
なんてのがあったとする. このメソッドは引数の2つの品種を掛け合わせる, なんてメソッドだとした時, ちょっとした問題が発生する.
それは, リンゴ×オレンジなんていう異種交配が始まってしまうパターン.
引数は「intかどうか」しかチェックしないため, 間違って (リンゴ,オレンジ) と別の種類の引数を入れてもコンパイルどころか実行まで通ってしまう. おおこわいこわい.
また, 上記例なら,
APPLE_FUJI == ORANGE_NAVEL
が trueを返すミラクル. これを回避するために, いちいち数値が被っていないかチェックが必要だったりとなかなか骨が折れる.
そこでEnum.

2. Enumの作り方

作り方はいたって簡単. 上記例ならリンゴ, オレンジはそれぞれ別物としてほしいので,
  public enum Apple {
    FUJI, PIPPIN, GRANNY_SMITH;
  }

  public enum Orange {
    NAVEL, TEMPLE, BLOOD;
  }
classや interfaceの代わりに enumを使う, 後は名前を列挙してやる. 「,(カンマ)」区切りで並べ, 必ず最後は「;(セミコロン)」でしめる.
こうすると, たとえばFUJIを呼び出したいなら,
Apple.FUJI
で呼び出せる. こうするとbreedメソッドも
public void appleBreed(Apple variety1, Apple variety2){}
とすれば, このメソッドはリンゴ同士でしかコンパイルが通らなくなる. 比較も,
Apple.FUJI == Orange.NAVEL;
Apple.FUJI == Apple.PIPPIN;
上はそもそも比較するものの型が違うとコンパイルエラーを吐いてくれるし, 下はもちろん falseが返る.
後からの追加も名前を足すだけで, 値の被りは名前の被りだけ気にすればいい.

3. 応用

こんな Enumの作り方もできちゃう.
public enum Skill {
  KAMEHAMEHA("かめはめ波", 1000);

  public String name;
  public int power;

  Skill(String name, int power) {
    this.name = name;
    this.power = power;
  }

  public String toString() {
    return name;
  }

}
唐突すぎる例( ゚д゚ )
たとえばかめはめ波という技の持つデータがすべて定数だった場合. これを Enumを使わずに管理するのはおそらく骨.
String KAMEHAMEHA_NAME ="かめはめ波";
int KAMEHAMEHA_POWER = 1000;
うん. 絶対事故る('A`).

そこで 「Enumにデータと振る舞いを持たせる」 ことをやってみる. KAMEHAMEHAは Skill型なので, 7行目からのコンストラクタが使える. 名前 KAMEHAMEHAが()で引数を持つのは, このコンストラクタを使うため. かめはめ波の powerを取り出したいなら,
int power = Skill.KAMEHAMEHA.power;
で取り出せる. 読みやすいし変にいろいろ参照しなくても OKなのは事故が起きにくいはず.
ちなみに12行目からのtoString()はEffectiveJava第 3章 10項「toStringを常にオーバーライドする」参照. 要するに,
System.out.println(Skill.KAMEHAMEHA);
としたときに, 「かめはめ波」と返ってきてくれた方が, 使う人にも優しい, ということ. 技を増やすときは同じように,
KAMEHAMEHA("かめはめ波", 1000),
TAIYOUKEN("太陽拳", 500);
とでも増やしてやればいい.



他にもメソッド持たせたりさらに応用もあるけどまだここまで.



かめはめ波とか出てきたのはだいたいここのせい.
たまに振り返ると固まっていなかった部分が矯正できて気分がいい+(・ω・0)*








まぁこの固めたのもいつまでもつやら…('A`)

0 件のコメント:

コメントを投稿

AWS CDKで立てたEC2インスタンスのTimeZoneとかいじりたかった話

EC2を立てることはできたけど、立てたインスタンスは UTCのままだし設定ファイルとかいちいちscpしてくるのはダルい。 当初UserDataでなんとかしようとしたものの、「書く量がヤバいしメンテしにくい」と悩んでいたところ見かけたのが  AWS::CloudFormation:...