Enum classes are used to restrict choices to a set of predetermined values. For example, you may wish to define a set of color constants such as Red, Green, and Blue. The color constants may later be used as an argument to a function or used in a when function. The compiler checks to make sure that only the allowed values are used when required. The type safety offered by enum classes can really valuable when reducing bugs and since the constants are named, the readability of the code is improved.
Let’s start with a basic definition of enum classes in Kotlin. We are going to begin with a Toppings enum class that offers Ketchup, Lettuce, Mayonnaise, and Tomatoes.
enum class Toppings { KETCHUP, MAYONNAISE, LETTUCE, TOMATO }
We can reference the values in toppings like so
val ketchup = Toppings.KETCHUP val mayo = Toppings.MAYONNAISE val lettuce = Toppings.LETTUCE val tomato = Toppings.TOMATO
or we can even use it as an argument to a function
fun printToppings(t : Toppings){ if (t == Toppings.KETCHUP){ print("Ketchup) } else { print("Not ketchup") } }
Enum classes also work great with the when function
val t = Toppings.LETTUCE val topping = when (t) { Toppings.KETCHUP -> "Ketchup" Toppings.MAYONNAISE -> "Mayonnaise" Toppings.LETTUCE -> "Lettuce" Toppings.TOMATO -> "Tomato" } print(topping)
Enum classes also have a name and ordinal property
val topping = Toppings.MAYONNAISE println(topping.name) //Prints MAYONNAISE println(topping.ordinal) //Prints 1
Advanced Enum Classes
Since enum classes are classes, they are free to have properties and methods like any other classes. Here is an example of an enum class with properties.
enum class Burgers(val burgerName : String){ CAPTAIN_JACK("Captain Pepper Jack Marrow Burger"), MY_FARRO_LADY("My Farro Lady Burger"), ENDIVE("Endive Had the Time of My Life Burger") }
Since each constant in the enum class is an instance of the enum class, we need to initialize all properties like we would any other class. We reference the enum’s property just like any other class property
val b = Burgers.CAPTAIN_JACK println(b.burgerName) //prints Captain Pepper Jack Marrow Burger
We can also define enum classes with methods, including abstract methods. This example shows an enum class where each constant in the enum class overrides the abstract method found in the enum.
enum class Family{ LOUISE { override fun sayCatchPhrase(): String = "I can smell fear on you" }, GENE { override fun sayCatchPhrase(): String = "I can't tell you my full name! You know Mom won't tell me my middle name!" }, TINA { override fun sayCatchPhrase(): String = "Here's a bunch of numbers that may look random, but they're my phone number" }, LINDA { override fun sayCatchPhrase(): String = "Teddy will eat whatever you put in front of him. Remember when he ate that receipt?" }, BOB { override fun sayCatchPhrase(): String = "So that's what a prostate exam is" }; abstract fun sayCatchPhrase() : String }
We call the method like we would on any other class.
val f = Family.BOB print(f.sayCatchPhrase()) //Prints So that's what a prostate exam is
Putting it Together
Here is an example program that shows off all three of the enum examples discussed.
package ch4.enumclasses enum class Toppings { KETCHUP, MAYONNAISE, LETTUCE, TOMATO } enum class Burgers(val burgerName : String){ CAPTAIN_JACK("Captain Pepper Jack Marrow Burger"), MY_FARRO_LADY("My Farro Lady Burger"), ENDIVE("Endive Had the Time of My Life Burger") } enum class Family{ LOUISE { override fun sayCatchPhrase(): String = "I can smell fear on you" }, GENE { override fun sayCatchPhrase(): String = "I can't tell you my full name! You know Mom won't tell me my middle name!" }, TINA { override fun sayCatchPhrase(): String = "Here's a bunch of numbers that my look random, but they're my phone number" }, LINDA { override fun sayCatchPhrase(): String = "Teddy will eat whatever you put in front of him. Remember when he ate that receipt?" }, BOB { override fun sayCatchPhrase(): String = "So that's what a prostate exam is" }; abstract fun sayCatchPhrase() : String } fun familyDemo(f : Family){ println("${f.name} says ${f.sayCatchPhrase()}") } fun main(args : Array<String>){ //Enum classes have a name and ordinal property println("Printing all values found in Toppings") Toppings.values().forEach { println("${it.name}: ${it.ordinal}") }.also { print("\n") } //We can also add our own properties like we did in Burgers println("Printing all values found in Burgers with burgerName") Burgers.values().forEach { println("${it.name}: ${it.ordinal} => ${it.burgerName}") }.also { print("\n")} //And we can even call methods on the enum class println("Printing all values found in Family with catchPhrase()") Family.values().forEach { println("${it.name}: ${it.ordinal} => ${it.sayCatchPhrase()}") } println() var burger = "Burger with " val topping = Toppings.LETTUCE //Enums work great with the when function burger += when (topping){ Toppings.KETCHUP -> "ketchup" Toppings.MAYONNAISE -> "mayonnaise" Toppings.LETTUCE -> "lettuce" Toppings.TOMATO -> "tomato" } println("Burger is => $burger \n") val family = Family.GENE familyDemo(family) }
We get the following output when the program is run.
Printing all values found in Toppings KETCHUP: 0 MAYONNAISE: 1 LETTUCE: 2 TOMATO: 3 Printing all values found in Burgers with burgerName CAPTAIN_JACK: 0 => Captain Pepper Jack Marrow Burger MY_FARRO_LADY: 1 => My Farro Lady Burger ENDIVE: 2 => Endive Had the Time of My Life Burger Printing all values found in Family with catchPhrase() LOUISE: 0 => I can smell fear on you GENE: 1 => I can't tell you my full name! You know Mom won't tell me my middle name! TINA: 2 => Here's a bunch of numbers that my look random, but they're my phone number LINDA: 3 => Teddy will eat whatever you put in front of him. Remember when he ate that receipt? BOB: 4 => So that's what a prostate exam is