これからプログラミングを学習したい方、Javaは難しそうでとっつきづらいという方のためのJavaプログラミング超入門連載です。最新のEclipseとJava 6を使い大幅に情報量を増やした、連載「Eclipseではじめるプログラミング」の改訂版となります
例えば、カレンダープログラムを作成したい場合は、1月から12月までをどのようにプログラム上で表現すればいいかを考える必要があります。トランプゲームを作成したい場合は、スーツ(スペード、ハート、ダイヤ、クラブ)について、同様に検討する必要があります。
こういった「あらかじめ要素数が分かっている定数の集合」を列挙して使うプログラムを作成するには、「列挙型(enumerated type)」の利用を検討するといいでしょう。
プログラムにおける列挙の表現方法はいくつかありますが、今回は「int enumパターン」「タイプセーフenumパターン」の紹介と、それらよりも使いやすい列挙型について順番に説明します。
EclipseでJavaプログラミングを始める準備がまだの方は、連載第1回の「Eclipse 3.4で超簡単Javaプログラミング基礎入門」で準備をしておいてください。
まずは、簡単な機能を持つカレンダープログラムを自作することを想像してみてください。皆さんはどのように1年をプログラム上で表現するでしょうか。
一番単純な方法は、int型の値を使う表現ですから、1年の各月を表示するとしたら、次のようなプログラムを作ることになるはずです。
package sample21; public class MonthList { public void exec() { for (int i = 1; i <= 12; i++) { System.out.println(i + "月"); } } public static void main(String[] args) { MonthList app = new MonthList(); app.exec(); } }
1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月
数値そのままで実現できるような単純なプログラムの場合は、このように簡単に実装できますが、各月の名前を英語で表示したい場合は、どうでしょう。すぐに思いつくのは、文字列の配列を用意して表現する方法かと思います。
ただしJavaの配列では、添字が0から開始するので、その点に注意が必要です。以下のMonthInEnglishクラスでは、ある月が英語で何というかを表示しています。
package sample21; public class MonthInEnglish { private String[] months = new String[] { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "OCTOBER", "SEPTEMBER", "NOVEMBER", "DECEMBER", }; public void exec() { System.out.println("2011年"); for (int i = 0; i < months.length; i++) { String s = (i + 1) + "月"; System.out.println(s + ":" + months[i]); } } public static void main(String[] args) { MonthInEnglish app = new MonthInEnglish(); app.exec(); } }
2011年 1月:JANUARY 2月:FEBRUARY 3月:MARCH 4月:APRIL 5月:MAY 6月:JUNE 7月:JULY 8月:AUGUST 9月:OCTOBER 10月:SEPTEMBER 11月:NOVEMBER 12月:DECEMBER
ところで、Javaにはカレンダーを表現するクラスは標準で備わってないのでしょうか。実は用意されていて、Javaでカレンダープログラムを作成する場合は、「java.util.Calendar」をよく使います。このクラスでは、月を表現する「JANUARY」などのstaticでfinalな変数が宣言されているので、これを使うこともできます。
実際の値は、「JANUARY」は0、「FEBRUARY」は1のようになっています。これらを使うと、例えば、次のようなプログラムが書けます。ここでは、2011年の各月に何日あるかまで表示しています。
package sample21; import java.util.Calendar; public class JavaUtilCalendarMonthList { private String[] months = new String[] { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER", }; public void exec() { System.out.println("2011年"); for (int i=0 ; i<months.length ; i++) { String s = (i+1) + "月"; switch (i) { case Calendar.FEBRUARY: s = s + ":" + months[i] + "(28日)"; break; case Calendar.APRIL: case Calendar.JUNE: case Calendar.SEPTEMBER: case Calendar.NOVEMBER: s = s + ":" + months[i] + "(30日)"; break; case Calendar.JANUARY: case Calendar.MARCH: case Calendar.MAY: case Calendar.JULY: case Calendar.AUGUST: case Calendar.OCTOBER: case Calendar.DECEMBER: s = s + ":" + months[i] + "(31日)"; break; } System.out.println(s); } } public static void main(String[] args) { JavaUtilCalendarMonthList app = new JavaUtilCalendarMonthList(); app.exec(); } }
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日)
ここで、finalについて説明しておきます。変数をfinalで修飾すると、その変数には一度だけ代入できます。
例えば、円周率の近似値を3.14として計算で使いたい場合は、PIという変数を用意して、そこへ3.14という値を設定したら変更したくないはずです。こういった変数を用意したいときに、次のように使います。
final double PI = 3.14;
ちなみに、このように、コンパイル時に定数となる式で初期化された基本データ(プリミティブ)型やjava.lang.String型のfinal変数を「定数変数(constant variable)」といいます。
参照型のオブジェクトをfinalで宣言された変数へ代入した場合は、注意が必要です。次のように用意した定数変数finalListに対して、新しいLinkedListのオブジェクトを代入できません。
つまり「finalList = new LinkedList<String>();」とするとエラーとなります。
final List<String> finalList = new LinkedList<String>(); // 次はコメントを外すとエラーとなる // finalList = new LinkedList<String>(); // 次の文は可能 finalList.add("Java");
これは、finalListに代入された参照値は変更できないからです。しかし、finalListが参照しているオブジェクトの状態は変更できます。つまり、「finalList.add("Java");」のように要素を追加できます。
さて、列挙の話に戻りましょう。JavaUtilCalendarMonthListのように、staticでfinalな変数を使って値を列挙することにより、数値を使うよりもプログラムの可読性が良くなります。
こういった方法による列挙の表現は、「int enumパターン(int enum pattern)」といわれていて、よく使われています。
次ページでは、int enumパターンの問題点や「タイプセーフenumパターン」、そして「enum」キーワードと列挙型について解説します。
Copyright © ITmedia, Inc. All Rights Reserved.