enum class
| 対応: | Kotlin 1.0(2016) |
|---|
『enum class』は決まった値の集合を型として定義する列挙型です。『values()』『valueOf()』などで列挙子の一覧や取得が行えます。
構文
// 基本的な enum class
enum class 列挙型名 {
定数1, 定数2, 定数3
}
// プロパティを持つ enum class
enum class 列挙型名(val プロパティ名: 型) {
定数1(値), 定数2(値)
}
構文一覧
| 構文 / プロパティ | 概要 |
|---|---|
| 列挙型名.values() | すべての列挙子を配列で返します。 |
| 列挙型名.valueOf("名前") | 名前に一致する列挙子を返します。存在しない場合は例外が発生します。 |
| 列挙子.ordinal | 列挙子の宣言順インデックス(0始まり)を返します。 |
| 列挙子.name | 列挙子の名前を文字列で返します。 |
| enumValues<T>() | 型パラメーターで列挙子の配列を取得します。 |
| enumValueOf<T>("名前") | 型パラメーターで名前から列挙子を取得します。 |
サンプルコード
enum_class.kt
// 曜日を表す enum class
enum class DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN
}
// プロパティを持つ enum class
enum class Color(val code: String) {
RED("#FF0000"),
GREEN("#00FF00"),
BLUE("#0000FF")
}
fun main() {
// name と ordinal を確認する
val day = DayOfWeek.WED
println(day.name) // WED
println(day.ordinal) // 2
// values() でループ処理する
for (d in DayOfWeek.values()) {
println("${d.ordinal}: ${d.name}")
}
// valueOf() で名前から列挙子を取得する
val c = Color.valueOf("BLUE")
println(c.code) // #0000FF
// when 式と組み合わせると便利
val msg = when (day) {
DayOfWeek.SAT, DayOfWeek.SUN -> "休日"
else -> "平日"
}
println(msg) // 平日
}
コンパイルして実行すると次のようになります。
kotlinc enum_class.kt -include-runtime -d enum_class.jar java -jar enum_class.jar WED 2 0: MON 1: TUE 2: WED 3: THU 4: FRI 5: SAT 6: SUN #0000FF 平日
よくあるミス
よくあるミス1: 『valueOf()』に存在しない名前を渡すと『IllegalArgumentException』が発生する。
NG例1 — valueOf() に存在しない名前を渡す
enum class Rank { BRONZE, SILVER, GOLD }
fun main() {
val r = Rank.valueOf("PLATINUM") // IllegalArgumentException
println(r)
}
enum_class_ok1.kt
enum class Rank { BRONZE, SILVER, GOLD }
fun main() {
val r = enumValues<Rank>().firstOrNull { it.name == "PLATINUM" }
println(r) // null
}
コンパイルして実行すると次のようになります。
kotlinc enum_class_ok1.kt -include-runtime -d enum_class_ok1.jar java -jar enum_class_ok1.jar null
よくあるミス2: 『ordinal』の数値に依存したコードを書くと、宣言順を変えたときに壊れる。
NG例2 — ordinal の数値をハードコードする
enum class Priority { LOW, MEDIUM, HIGH }
fun main() {
if (Priority.HIGH.ordinal == 2) println("HIGH は3番目")
// 宣言順を変えると ordinal の値が変わる
}
enum_class_ok2.kt
enum class Priority(val level: Int) { LOW(1), MEDIUM(5), HIGH(10) }
fun main() {
val p = Priority.HIGH
println(p.level) // 10(宣言順に依存しない)
println(p.name) // HIGH
}
コンパイルして実行すると次のようになります。
kotlinc enum_class_ok2.kt -include-runtime -d enum_class_ok2.jar java -jar enum_class_ok2.jar 10 HIGH
よくあるミス3: 『when』式で全列挙子を網羅せずに『else』を使うと、新しい列挙子を追加したときに見落としが起きる。
NG例3 — when に else を書いて網羅性を失う
enum class Color { RED, GREEN, BLUE }
fun describe(c: Color): String = when (c) {
Color.RED -> "赤"
else -> "その他" // GREEN/BLUE の分岐が抜けていても気づけない
}
enum_class_ok3.kt
enum class Color { RED, GREEN, BLUE }
fun describe(c: Color): String = when (c) {
Color.RED -> "赤"
Color.GREEN -> "緑"
Color.BLUE -> "青"
// 全列挙子を網羅すれば else 不要。新しい列挙子を追加するとコンパイルエラーになる
}
fun main() {
println(describe(Color.BLUE)) // 青
}
コンパイルして実行すると次のようになります。
kotlinc enum_class_ok3.kt -include-runtime -d enum_class_ok3.jar java -jar enum_class_ok3.jar 青
概要
『enum class』は定数の集合を型安全に扱うための仕組みです。すべての列挙子は自動的に『name』(宣言名の文字列)と『ordinal』(0始まりのインデックス)を持ちます。
コンストラクタにプロパティを定義すると、各列挙子に異なる値を持たせることができます。『valueOf()』に存在しない名前を渡すと『IllegalArgumentException』が発生するため、不明な文字列を変換する場合は『try-catch』や『enumValues()』でのフィルタリングを検討してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。