Enum Classes
Part of the Object Oriented Programming section of Coddy's Kotlin journey. Lesson 33 of 57.
An enum class declares a type with a fixed set of values, its constants. Each constant is an object of the enum with a name and an ordinal, its position starting at 0. entries lists them in order:
enum class Direction { NORTH, EAST, SOUTH, WEST }Inside main:
val d = Direction.EAST
println(d)
println(d.ordinal)
println(Direction.entries)Output:
EAST
1
[NORTH, EAST, SOUTH, WEST]Enum constants can have properties, passed to the enum's constructor, and the enum can declare methods. A semicolon ends the list of constants before the members:
enum class Coin(val cents: Int) {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
fun label() = "${name.lowercase()} ($cents c)"
}Inside main:
println(Coin.DIME.label())
println(Coin.entries.sumOf { it.cents })Output:
dime (10 c)
41A when over an enum that lists every constant needs no else, and the compiler reports a constant that is missing. valueOf("SOUTH") finds a constant by its exact name and throws for an unknown one, so input is usually matched with entries.find:
enum class Direction { NORTH, EAST, SOUTH, WEST }
fun turnRight(d: Direction) = when (d) {
Direction.NORTH -> Direction.EAST
Direction.EAST -> Direction.SOUTH
Direction.SOUTH -> Direction.WEST
Direction.WEST -> Direction.NORTH
}
fun parse(text: String) = Direction.entries.find { it.name == text.uppercase() }Inside main:
println(turnRight(Direction.valueOf("SOUTH")))
println(parse("north"))
println(parse("up"))Output:
WEST
NORTH
nullA constant can have its own body and override a method there. Declaring the method abstract in the enum forces every constant to implement it:
enum class Op(val symbol: String) {
PLUS("+") {
override fun apply(a: Int, b: Int) = a + b
},
TIMES("*") {
override fun apply(a: Int, b: Int) = a * b
};
abstract fun apply(a: Int, b: Int): Int
}Inside main:
for (op in Op.entries) println("6 ${op.symbol} 3 = ${op.apply(6, 3)}")Output:
6 + 3 = 9
6 * 3 = 18Challenge
EasyComplete the enum Size with the constants SMALL (250 ml, price 300), MEDIUM (350 ml, 380) and LARGE (500 ml, 450), prices in cents. label() returns medium (350 ml): 3.80, and upsize() returns the next larger size, or the same size for LARGE. The companion's parse(text) finds a size by its name ignoring case, or by its first letter (s, M), and returns null otherwise.
The supplied code reads orders such as medium, L or up small (the upsized drink) and prints each label or unknown size x, and finally total: 11.10.
Your code goes in Size.kt. Main.kt holds the supplied input/output code and cannot be edited.
Try it yourself
fun main() {
// Supplied input/output code: keep it as it is
val input = generateSequence(::readLine).toList()
var total = 0
for (line in input) {
val upsize = line.startsWith("up ")
val size = Size.parse(line.removePrefix("up "))
if (size == null) {
println("unknown size $line")
continue
}
val chosen = if (upsize) size.upsize() else size
println(chosen.label())
total += chosen.price
}
println("total: %d.%02d".format(total / 100, total % 100))
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesPrimary Constructorsinit Blocks and ValidationSecondary ConstructorsRecap - Library Card4Inheritance
Open Classes and SubclassesOverriding Memberssuper and ConstructorsAbstract ClassesRecap - Staff Directory7Special Classes
Data ClassesEnum ClassesSealed Hierarchiesequals, hashCode, toStringRecap - Order Tracker2Properties and Encapsulation
Custom AccessorsVisibility ModifiersPrivate Setterslazy and lateinitRecap - Bank Account5Interfaces
Declaring InterfacesDefault MethodsMultiple InterfacesInterfaces as TypesRecap - Payment Methods8Generics
Generic FunctionsGeneric ClassesType ConstraintsVariance With in and outRecap - Priority Queue11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Kotlin playground