連載
» 2011年03月03日 00時00分 公開

7ステップで理解するJavaでの列挙型/enum使用法【改訂版】Eclipseではじめるプログラミング(21)(3/3 ページ)

[小山博史,株式会社ガリレオ]
前のページへ 1|2|3       

【Step 5】列挙型を使って日本語でも各月の名前を表示

 もう1つ列挙型の例を見てみましょう。int enumパターンでは複数の値をまとめて管理できませんが、メソッドやフィールドを持つ列挙型を使うことにより実現できます。ここでは、列挙定数の文字列だけでなく、日本語でも各月の名前を表示できるようにしてみます。

package sample21;
 
public class EnumJapaneseMonthList {
    enum Month {
        JANUARY("睦月"),
        FEBRUARY("如月"),
        MARCH("弥生"),
        APRIL("卯月"),
        MAY("皐月"),
        JUNE("水無月"),
        JULY("文月"),
        AUGUST("葉月"),
        SEPTEMBER("長月"),
        OCTOBER("神無月"),
        NOVEMBER("霜月"),
        DECEMBER("師走");
  
        private String name;
        Month(String name) { this.name = name; }
        public String getName() { return name; }
    }
    public void exec() {
        for (Month m : Month.values()) {
          System.out.println(m + ":" + m.getName());
        }
    }
    public static void main(String[] args) {
      EnumJapaneseMonthList app = new EnumJapaneseMonthList();
      app.exec();
    }
}
sample21/EnumJapaneseMonthList.java
JANUARY:睦月
FEBRUARY:如月
MARCH:弥生
APRIL:卯月
MAY:皐月
JUNE:水無月
JULY:文月
AUGUST:葉月
SEPTEMBER:長月
OCTOBER:神無月
NOVEMBER:霜月
DECEMBER:師走
実行結果

 EnumJapaneseMonthListクラス内のMonth型では、文字列を引数とするコンストラクタを用意して、そこで与えられた文字列をnameフィールドへ保持しています。

【Step 6】管理しやすい「java.utilEnumMap」を使う

 列挙定数と対応するメッセージを一緒に管理したり、列挙定数と対応する整数値やオブジェクトを一緒に管理したりしたい場合があります。そんなときは、「java.util.EnumMap」クラスを使います。

 次の例では、各月の名前と、整数値を対応させて、EnumMapを使って一緒に管理しています。int enumパターンで実装した「2011年の各月に何日あるか表示するプログラム」と同じ動作をするプログラムです。

package sample21;
 
import java.util.EnumMap;
 
public class EnumMapMonthList {
    private enum Month {
      JANUARY, FEBRUARY, MARCH, APRIL,
      MAY, JUNE, JULY, AUGUST,
      SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER;
    }
    private EnumMap<Month, Integer> monthMap;
  
    public EnumMapMonthList() {
        monthMap = new EnumMap<Month, Integer>(Month.class);
        monthMap.put(Month.JANUARY, 1);
        monthMap.put(Month.FEBRUARY, 2);
        monthMap.put(Month.MARCH, 3);
        monthMap.put(Month.APRIL, 4);
        monthMap.put(Month.MAY, 5);
        monthMap.put(Month.JUNE, 6);
        monthMap.put(Month.JULY, 7);
        monthMap.put(Month.AUGUST, 8);
        monthMap.put(Month.SEPTEMBER, 9);
        monthMap.put(Month.OCTOBER, 10);
        monthMap.put(Month.NOVEMBER, 11);
        monthMap.put(Month.DECEMBER, 12);
    }
    public void exec() {
        System.out.println("2011年");
        for (Month m : Month.values()) {
            String s = monthMap.get(m) + "月";
            switch (m) {
            case FEBRUARY:
                s = s + ":" + m + "(28日)";
                break;
            case APRIL:
            case JUNE:
            case SEPTEMBER:
            case NOVEMBER:
                s = s + ":" + m + "(30日)";
                break;
            case JANUARY:
            case MARCH:
            case MAY:
            case JULY:
            case AUGUST:
            case OCTOBER:
            case DECEMBER:
                s = s + ":" + m + "(31日)";
                break;
            }
            System.out.println(s);
        }
    }
    public static void main(String[] args) {
        EnumMapMonthList app = new EnumMapMonthList();
        app.exec();
    }
}
sample21/EnumMapMonthList.java

 switch文の判別式に、列挙型の変数を指定している点、case文では列挙定数を指定する点に注目してください。

2011年
1月:JANUARY(31日)
2月:FEBRUARY(28日)
3月:MARCH(31日)
4月:APRIL(30日)
5月:MAY(31日)
6月:JUNE(30日)
7月:JULY(31日)
8月:AUGUST(31日)
9月:SEPTEMBER(30日)
10月:OCTOBER(31日)
11月:NOVEMBER(30日)
12月:DECEMBER(31日)
実行結果

 ここでは、数値を対応させていますが、例えば、JANUARYに「JAN.」という略称を対応させたい場合は、「EnumMap」とします。

【Step 7】「java.util.EnumSet」クラスでビット和操作

 列挙定数にビット演算しやすい値を指定したいときがあります。

int enumパターンでビット和操作

 例えば、上下左右の矢印キーを組み合わせて使えるようにしたいとします。これは、int enumパターンでの実装なら、各キーの値を下記のように対応させることにより、ビット和操作などができるようになります。

package sample21;
 
import java.util.ArrayList;
import java.util.List;
 
public class ArrowKeysSample {
    class ArrowKeys {
        public static final int UP = 0x01;
        public static final int RIGHT = 0x02;
        public static final int DOWN = 0x04;
        public static final int LEFT = 0x08;
    }
  
    public void exec() {
        List<Integer> keys = new ArrayList<Integer>();
        keys.add(ArrowKeys.UP);
        keys.add(ArrowKeys.RIGHT);
        keys.add(ArrowKeys.UP+ArrowKeys.RIGHT);
        keys.add(ArrowKeys.DOWN);
        keys.add(ArrowKeys.UP+ArrowKeys.DOWN);
        keys.add(ArrowKeys.UP+ArrowKeys.RIGHT + ArrowKeys.DOWN+ArrowKeys.LEFT);
        for (int e : keys) {
            System.out.print(e + ":");
            if ((e & ArrowKeys.UP) != 0) {
                System.out.print("UP, ");
            }
            if ((e & ArrowKeys.RIGHT) != 0) {
                System.out.print("RIGHT, ");
            }
            if ((e & ArrowKeys.DOWN) != 0) {
                System.out.print("DOWN, ");
            }
            if ((e & ArrowKeys.LEFT) != 0) {
                System.out.print("LEFT, ");
            }
                System.out.println("");
        }
    }
    public static void main(String[] args) {
        ArrowKeysSample app = new ArrowKeysSample();
        app.exec();
    }
}
sample21/EnumMapMonthList.java
1:UP, 
2:RIGHT, 
3:UP, RIGHT, 
4:DOWN, 
5:UP, DOWN, 
15:UP, RIGHT, DOWN, LEFT, 
実行結果

 このプログラムでは、例えば、「UPの矢印キーが押下されているときは1」「UPとRIGHTの矢印キーが同時に押下されているときは3」「全部が押下されているときは15」となっていて、どのキーが押されているかが、int値から分かります。「UP」「RIGHT」といった定数がint値の各ビットと対応付けされているので、int値の対応するビットが0なのか、1なのかで、押下を判定できるのです。

ビット和操作を列挙型で実現できる「java.util.EnumSet」クラス

 同様なプログラムを、int enumパターンではなく列挙型でできないでしょうか。実は、Javaでは「java.util.EnumSet」クラスが用意されていて、実現可能です。

package sample21;
 
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
 
public class EnumArrowKeysSample {
    enum ArrowKeys { UP, RIGHT, DOWN, LEFT }
 
    public void exec() {
        List<EnumSet<ArrowKeys>> keys = new ArrayList<EnumSet<ArrowKeys>>();
        keys.add(EnumSet.of(ArrowKeys.UP));
        keys.add(EnumSet.of(ArrowKeys.RIGHT));
        keys.add(EnumSet.of(ArrowKeys.UP, ArrowKeys.RIGHT));
        keys.add(EnumSet.of(ArrowKeys.DOWN));
        keys.add(EnumSet.of(ArrowKeys.UP, ArrowKeys.DOWN));
        keys.add(EnumSet.allOf(ArrowKeys.class));
        for (EnumSet<ArrowKeys> e : keys) {
            System.out.print(e + ":");
            if (e.contains(ArrowKeys.UP)) {
                System.out.print("UP, ");
            }
            if (e.contains(ArrowKeys.RIGHT)) {
                System.out.print("RIGHT, ");
            }
            if (e.contains(ArrowKeys.DOWN)) {
                System.out.print("DOWN, ");
            }
            if (e.contains(ArrowKeys.LEFT)) {
                System.out.print("LEFT, ");
            }
            System.out.println("");
        }
    }
    public static void main(String[] args) {
        EnumArrowKeysSample app = new EnumArrowKeysSample();
        app.exec();
    }
}
sample21/EnumArrowKeysSample.java
[UP]:UP, 
[RIGHT]:RIGHT, 
[UP, RIGHT]:UP, RIGHT, 
[DOWN]:DOWN, 
[UP, DOWN]:UP, DOWN, 
[UP, RIGHT, DOWN, LEFT]:UP, RIGHT, DOWN, LEFT, 
実行結果

 このプログラムでは、EnumSet型のオブジェクトで矢印キーの押下を表現しています。

 例えば、UPの矢印キーが押下されているときは「EnumSet.of(ArrowKeys.UP)」、UPとRIGHTの矢印キーが同時に押下されているときは「EnumSet.of(ArrowKeys.UP, ArrowKeys.RIGHT)」、全部が押下されているときは「EnumSet.allOf(ArrowKeys.class)」、となっています。

次回は、Java 5からの肝「アノテーション」

 ある値を列挙してプログラムで利用したい場合は、Javaでは列挙型を使えばいいことが理解できたでしょうか。Javaのバージョンによっては(5よりも前の場合)列挙型が使えませんから、その場合はタイプセーフenumパターンを使います。

 また、サンプルプログラムでちょっとした値を列挙したい場合や、列挙型を使うまでもない場合は、int enumパターンが使えます。作成したいプログラム、Javaのバージョンといったプログラミング環境に合わせて、どれを使うか決めるといいでしょう。

 本記事では、列挙型の基本的な使い方について説明しましたが、インターフェイスを実装したり、独自のメソッドやフィールドを宣言して使う方法もあります。Javaの列挙型はいろいろな場面で利用できますから、興味がある読者は、enumについてさらに調べてみてください。

 次回は、Java 5からの肝といえる「アノテーション」について説明する予定です。今回作ったサンプルのソースコードはこちらからダウンロードできます。

筆者紹介

小山博史(こやま ひろし)

情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)bugs(J)の活動へも参加している。

著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。



「【改訂版】Eclipseではじめるプログラミング」バックナンバー
前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。