AIにenumの基礎を聞いてみた――列挙型の型安全性を理解するAIアシスト時代のJavaプログラミング入門(9)

対話型AI(人工知能)にアドバイスを受けながら進めるJavaプログラミングの入門連載。今回も、オブジェクト指向プログラミングの機能として、列挙型を学習します。特別なクラスとしての列挙型を、その意義とともに理解しましょう。

» 2025年12月11日 05時00分 公開

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「AIアシスト時代のJavaプログラミング入門」のインデックス

連載:AIアシスト時代のJavaプログラミング入門

本連載のサンプルコードをGitHubで公開しています。こちらからダウンロードしてみてください。


今回のテーマは列挙型(enum)

 対話型AI(人工知能)にアドバイスを受けながら進めるJavaプログラミングの入門連載「AIアシスト時代のJavaプログラミング入門」前回は、オブジェクト指向の実用的な機能を知りたいということで、「Javaのオブジェクト指向機能を使った実用的な機能を知りたい。コードは不要です。」という質問を、Visual Studio Code(以降、VS Code)からGitHub Copilot(以降、Copilot)に投げてみました(図1)。

図1 「Javaのオブジェクト指向機能を使った実用的な機能を知りたい。コードは不要です。」の回答(再掲) 図1 「Javaのオブジェクト指向機能を使った実用的な機能を知りたい。コードは不要です。」の回答(再掲)

 前回は、ここからジェネリクスとコレクションをピックアップして学んだわけですが、まだまだ実用的な機能はありそうです。そこで今回も、オブジェクト指向の延長として、実用的な用途に踏み込んでいきます。今回は8番目の「列挙型(enum)」をピックアップします。なお、モデルには今回も引き続きGPT-5 miniを使っていきます。

列挙型とは

 列挙型には、「enum」と付記されています。enumのフルスペルはenumerateであり、列挙するという意味ですが、冒頭の図1では、以下のように説明されています。

・定数集合に振る舞いを持たせる。状態管理やモード表現に便利。

 「振る舞い」とはメソッドのことと想像できるので、ここでは「定数集合」というのがポイントになりそうです。前回同様に、「列挙型の目的を説明して。初心者でも分かるように専門用語はできるだけ控えて簡潔にコードなしで。」と投げてみました(図2)。

図2 列挙体の目的を説明してもらった回答 図2 列挙体の目的を説明してもらった回答

 図2には「限られた選択肢を分かりやすくまとめる」とあるので、値というのは定数(値の変化しない変数)で、それをまとめるのが列挙型のようです。また、「曜日・状態・方向など関連する値を1か所で管理できる」というのが、状態管理やモード表現に便利ということのようです。分かりやすいのは曜日ですが、月曜(Monday)、火曜(Tuesday)、日曜(Sunday)などと7個あります。このような限られた選択肢をまとめるのが列挙型だと理解できますね。

【補足】質問がくどい?

 以降もそうですが、AIへの質問がくどいと感じられるかもしれません。これは、前回も述べたように、モデルとして採用しているGPT-5 miniの性格によるものです。単純な質問でも網羅性の高い回答やサンプルを提示してくるので、ここではできるだけ基本的な機能について説明してもらうために、ややくどい質問にしています。

列挙型を使わずに曜日を扱う

 このような列挙型の意義を具体的に確かめるために、まずは列挙型を使わずに通常のクラスを用いて、曜日を表す定数の集合を使うコードを示してもらいましょう。前回でも行ったように、「basicプロジェクトを基にenumプロジェクトを作り、列挙型を使わずに曜日を定数で表現したサンプルコードを入れて。」と投げて一連の作業を実行してもらいました(図3)。

図3 列挙型を使わないコードを作成してもらった結果 図3 列挙型を使わないコードを作成してもらった結果

 enumプロジェクトに、WeekdayConstants.javaとWeekdayApp.javaが作成されます。列挙型を使わないので、これまでの知識+αで読み解けるはずですね。まずはWeekdayConstants.javaに説明を入れてみました(図4)。

図4 生成されたWeekdayConstants.javaのコード 図4 生成されたWeekdayConstants.javaのコード

 重要なのは(2)の7つの定数宣言(定数の集合)です。曜日に相当するMONDAYからSUNDAYに順番に1からの整数値を割り当てています。また、(2)(3)のようにメソッドを定義できます。この例は通常のクラスですから、当たり前ですね。

【補足】定数の宣言

 定数とは、値の変わらない変数を言います。図4で、変数宣言の形式と似ているが、少し違っていることに気付いたでしょう。定数は変数と同じように宣言しますが、finalキーワードを付けます。finalなので、これ以上値が変わらない、最終値というわけです。

 このクラスをどのように使うのかを確かめるために、利用側であるWeekdayApp.javaの方も見てみます(図5)。

図5 生成されたWeekday.javaのコード 図5 生成されたWeekday.javaのコード

 ここも、重要なのは(1)の変数宣言です。WeekdayConstantsクラスの定数MONDAYでint型変数として初期化しています。これは、WeekdayConstantsクラスにおいて、MONDAYなどがint型の定数として宣言されているからでした。続くメソッド呼び出しについてもここでは触れませんが、同じようにTUESDAYなどを初期値とする整数型変数を宣言して使うというようにイメージしやすいですね。

 しかしながら、図3の「注意点(簡潔)」で示されている点に着目すると、この方法は型安全性に問題がありそうです。図4においてWeekdayConstants.MONDAYはint型なので、図5の(4)のようにクラスで定義されていない値(この場合は99)も受け入れてしまいます。とすると、曜日を安全に扱えないということになりますね。

図6 列挙型を使わずに曜日を扱う 図6 列挙型を使わずに曜日を扱う

 図3には、PowerShellでの実行方法が示されているので、最後に実行結果を見てみましょう(図7)。この実行結果からコードを振り返ってみてください。

図7 列挙型を使わないコードの実行結果 図7 列挙型を使わないコードの実行結果

こんな質問をしてみたい!

 図4の(1)では、コンストラクタにprivateが付いていました。これまではコンストラクタにはpublicを付けていたので、意味が違いそうです。「コンストラクタをprivateにする意味は?」と聞いてみると、コンストラクタの役割や呼び出される場面への理解が、より深まるかもしれませんよ。

列挙型で曜日を扱う(基本形)

 定数の集合の取り得る値を明確化する仕組みとして、列挙型を使います。図4のコードを、列挙型を使うように修正してもらいましょう。「WeekdayConstants.javaをWeekdayEnum.javaとして列挙型を使うようにできるだけシンプルに置き換えて。WeekdayApp.javaにも利用コードを追加して。元のコードを残すこと。」と投げてみました(図8)。「元のコードを残すこと。」と加えたのは、既存のコード(図5のコード)を消去してしまうことがあるからです。

図8 列挙型を使うコードを作成してもらった結果 図8 列挙型を使うコードを作成してもらった結果

 enumプロジェクトに、WeekdayEnum.javaが追加され、WeekdayApp.javaが更新されます。WeekdayEnum.javaは図10のような内容で、メソッド定義部分を除くと非常にシンプルです。これらのコードについて説明してもらいましょう。「生成されたWeekdayEnum.javaのコードを、専門用語を使って要点のみ説明して。コードの説明以外は不要です。」と投げてみました(図9)。

図9 列挙型の基本機能を使うコードの説明 図9 列挙型の基本機能を使うコードの説明

 だいぶ簡潔な説明ですが、これを基に対応するコードに簡単な説明を入れてみました(図10)。

図10 生成されたWeekdayEnum.javaのコード 図10 生成されたWeekdayEnum.javaのコード

 (1)のように、列挙型はclassキーワードではなくenumキーワードで定義します。列挙定数として、(2)のように各曜日に相当するMONDAY、TUESDAY、WEDNESDAYなどを記述していくのが、クラスとの大きな違いです。各列挙定数には、大文字で名前を付けていくのが基本です。WeekdayConstantsクラスでは整数型定数を定義していましたが、列挙型では列挙定数として名前だけ指定すれば済みます。

 列挙型には、(3)のように振る舞い(メソッド)を持たせることができます。(4)のように==演算子で同一性の比較ができる他、(5)のように列挙型に用意されるメソッド(ここれはname)を利用することができます。

【補足】java.lang.Enumクラス

 AIの回答では特に触れられていませんでしたが、全ての列挙型はjava.lang.Enumクラスを継承します。クラスの継承のようなextendsキーワードは不要で、暗黙のうちに継承されます。java.lang.Enumクラスは(5)のnameメソッドをはじめとして表1に挙げるメソッドを実装しており、全ての列挙型で利用できます。

メソッド 概要
name() 列挙定数の名前に相当する文字列を返す(MONDAY→"MONDAY")
values() 列挙定数のリストを返す(拡張for文などで利用できる)
ordinal() 列挙定数の内部値(0からの整数)を返す
valueOf() 文字列から列挙定数を返す("MONDAY"→MONDAY)
表1 java.lang.Enumクラスのメソッド

 列挙型を利用する、WeekdayApp.javaも見てみます(図11)。

図11 更新されたWeekdayApp.javaのコード(追加部のみ) 図11 更新されたWeekdayApp.javaのコード(追加部のみ)

 列挙型のインスタンスは(1)のようにnewを使わずに「WeekdayEnum.MONDAY」のように「列挙型.値」の形式で宣言します。後は、変数によって列挙型の値(MONDAYなど)を直接参照したり、メソッドを呼び出すことができます。

 定数版ではint型の変数であったのに対して、ここではWeekdayEnum型となっている点にも注目です。変数eTodayにはWeekdayEnumクラスのインスタンス以外は入らないということになり、これが型安全性につながるということですね。もし、MONDAYとかでなく99といった値を直接入れようとしたら、コンパイル時点でエラーとしてくれるわけです。

 (2)のように列挙型インスタンスを表示しようとすると、オーバーライドされたtoStringメソッドによって識別子文字列が取得されます。(4)と(5)では、列挙体に備わっているvaluesメソッドとordinalメソッドを使っています。

図12 列挙型で曜日を扱う(基本形) 図12 列挙型で曜日を扱う(基本形)

 前節と同様に、最後に実行結果を見てみましょう(図13)。

図13 列挙型の基本機能を使うコードの実行結果 図13 列挙型の基本機能を使うコードの実行結果

こんな質問をしてみたい!

 図2には、「処理の分岐や表示が簡単になる」とも示されていました。提示されたコードにはそれに相当するものがありませんでしたが、このコードを追加してもらうと、列挙型の用途への理解がさらに深まるかもしれませんよ!

列挙型で曜日を扱う(発展形)

 ここまでで、列挙型のごくごく基本的なところを理解できたと思います。取り得る値(列挙定数)の一覧を持ち、メソッドも定義できるということですね。しかしながら、列挙型の機能はこれだけではないはずです。そこで、「WeekdayEnum.javaをWeekdayEnumAdvance.javaとして列挙型の進んだ機能を使うように置き換えて。WeekdayApp.javaにも利用コードを追加して。元のコードを残すこと。」と投げてみました(図14)。

図14 列挙型の進んだ機能を使うコードを作成してもらった結果 図14 列挙型の進んだ機能を使うコードを作成してもらった結果

 enumプロジェクトに、WeekdayEnumAdvance.javaが追加され、WeekdayApp.javaが更新されます。WeekdayEnumAdvance.javaはかなり長く、一見何をしているのか分からないので、これらのコードについて説明してもらいましょう。「生成されたWeekdayEnumAdvance.javaのコードを、専門用語を使って要点のみ説明して。コードの説明以外は不要です。」と投げてみました(図15)。

図15 列挙型の進んだ機能を使うコードの説明 図15 列挙型の進んだ機能を使うコードの説明

 これもかなり簡潔な説明ですが、これを基に対応するコードに簡単な説明を入れてみました(図16)。

図16 生成されたWeekdayEnumAdvance.javaのコード 図16 生成されたWeekdayEnumAdvance.javaのコード

 以下、図16の赤字を補足する形で、図15の回答も使いながらコードを説明します。

・不変フィールドを持ち、コンストラクタで初期化する

 (3)のように、列挙型はクラスと同様にフィールドを持つことができます。フィールドは自由に定義でき、ここではnumber(1からの整数)、shortName(短縮名)、weekend(週末フラグ)の3つが定義されています。finalが指定されているように、初期化されたら不変のフィールドとなっています。

 フィールドは(5)のコンストラクタで初期化されます。コンストラクタは(2)のように列挙定数ごとに呼び出されます。つまり列挙定数は、それぞれがWeekdayEnumAdvance型のインスタンスということです。列挙型では、インスタンス化は自動で行われ、通常のクラスのようにnewを使って明示的に行う必要はありません。

【補足】不変フィールド

 定数のようにfinalキーワードを付けてフィールドを宣言すると、それは不変フィールドになります。初期化したら以降は値が変わりません(不変)。定数と異なり、staticが付いていないことに注意しましょう。

・メソッドの定義

 WeekdayEnumAdvance型では、(6)にある上記の不変フィールドに対するゲッターメソッド(getNumber、getShortName、isWeekend)の他、next、previous、fromNumberというユーティリティーメソッドも(7)のように定義しています。ユーティリティーメソッドでは、列挙型で使えるvaluesメソッド、ordinalメソッドも使われています。

 (8)のtoStringメソッドの実装は、WeekdayEnum型とは変わっていて、「識別子文字列(短縮形)」と整形して文字列化しています。この当たりは、継承とオーバーライドの仕組みで理解できますね。

 WeekdayEnumAdvance型を利用する、WeekdayApp.javaの該当箇所も見てみます(図17)。

図17 更新されたWeekdayApp.javaのコード(追加部のみ) 図17 更新されたWeekdayApp.javaのコード(追加部のみ)

 ほとんど、これまでの説明で読み解けると思います。ただし1カ所だけ、新しい内容があります。(4)のEnumSetを使った例です。EnumSetとは、前回に説明したコレクション、特にセットの一種です。列挙型に特化されており、列挙型のインスタンスを受け入れ、要素の存在を確認するcontainsメソッドなどを利用できます。

図18 列挙型で曜日を扱う(発展形) 図18 列挙型で曜日を扱う(発展形)

 これまでと同様に、最後に実行結果を見てみましょう(図19)。

図19 列挙型の進んだ機能を使うコードの実行結果 図19 列挙型の進んだ機能を使うコードの実行結果

こんな質問をしてみたい!

 図16の(4)については、特に説明をしていませんでした。この部分は、(7)のfromNumberメソッドで使うHashMapを作成していますが、staticで始まるブロックなど、見慣れない形式をしています。staticは他の場所にも登場するので、クラスや列挙型でstaticを使う意味を聞いてみると、クラスとインスタンスの関係への理解が、より進むかもしれませんよ。

まとめ

 今回は、特別なクラスとしての列挙型をAIに聞きながら学習しました。

 次回は、不変オブジェクトとレコード型を学習します。

筆者紹介

WINGSプロジェクト 山内直

WINGSプロジェクト所属のテクニカルライター。出版社秀和システムを経てフリーランスとして独立。ライター、編集者、開発者、講師業に従事。屋号は「たまデジ。」。

たまデジ。 | たまプラーザで生活、仕事する。(https://naosan.jp/

WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティー(代表山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手掛ける。2021年10月時点での登録メンバーは55人で、現在も執筆メンバーを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。

サーバーサイド技術の学び舎 - WINGS(https://wings.msn.to/
RSS(https://wings.msn.to/contents/rss.php
X: @WingsPro_info(https://x.com/WingsPro_info
Facebook(https://www.facebook.com/WINGSProject


Copyright © ITmedia, Inc. All Rights Reserved.

アイティメディアからのお知らせ

スポンサーからのお知らせPR

注目のテーマ

人に頼れない今こそ、本音で語るセキュリティ「モダナイズ」
4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

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

メールマガジン登録

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