In this chapter, we're going to introduce the concept of enum classes. Let's start with an example. Suppose that you’re implementing a payment method that has to support three possible options: cash payment, card payment, and bank transfer. The most basic way to represent a fixed set of values in Kotlin is an enum class. Inside its body, we list all the values, divided by a comma. We name values using UPPER_SNAKE_CASE notation (e.g., BANK_TRANSFER). Enum class elements can be referenced by the enum name, followed by a dot, and then the value name (e.g., PaymentOption.CASH). All values are typed as the enum class type.
enum class PaymentOption {
CASH,
CARD,
TRANSFER,
}
fun printOption(option: PaymentOption) {
println(option)
}
fun main() {
val option: PaymentOption = PaymentOption.CARD
println(option) // CARD
printOption(option) // CARD
}
Each enum class has the following companion object elements:
entries property, which keeps a list of all the values of this enum class. It is a modern replacement of the values function, that returns an array of elements[^13_3].
valueOf function, which parses a string into a value matching its name (this is case-sensitive) or throws an exception.
enum class PaymentOption {
CASH,
CARD,
TRANSFER,
}
fun main() {
val option: PaymentOption =
PaymentOption.valueOf("TRANSFER")
println(option)
println("All options: ")
val paymentOptions: List<PaymentOption> =
PaymentOption.entries
for (paymentOption in paymentOptions) {
println(paymentOption)
}
}
// TRANSFER
// All options:
// CASH
// CARD
// TRANSFER
Instead of these methods, we can also use the top-level enumValues and enumValueOf functions.
enum class PaymentOption {
CASH,
CARD,
TRANSFER,
}
fun main() {
val option = enumValueOf<PaymentOption>("TRANSFER")
println(option)
println("All options: ")
val paymentOptions = enumValues<PaymentOption>()
for (paymentOption in paymentOptions) {
println(paymentOption)
}
}
// TRANSFER
// All options:
// CASH
// CARD
// TRANSFER
As you can see, enum elements keep their values in order. This order is important. Each enum value has two properties:
name - the name of this value,
ordinal - the position of this value (starting from 0).
enum class PaymentOption {
CASH,
CARD,
TRANSFER,
}
fun main() {
val option = PaymentOption.TRANSFER
println(option.name) // TRANSFER
println(option.ordinal) // 2
}
Each enum class is a subclass of the abstract class Enum. This superclass guarantees the name and ordinal properties. Enum classes have properties that implement toString, equals, and hashCode, but, unlike data classes, they also have compareTo (their natural order is the order of the elements in the body).
Enum values can be used inside when-conditions. Moreover, there is no need to use the else-branch when all possible enum values are covered.
fun transactionFee(paymentOption: PaymentOption): Double =
when (paymentOption) {
PaymentOption.CASH -> 0.0
PaymentOption.CARD, PaymentOption.TRANSFER -> 0.05
}
Enum classes are very convenient because they can be easily parsed or stringified. They are a popular way to represent a finite set of possible values.
Data in enum values
In Kotlin, each enum value can hold a state. It is possible to define a primary constructor for an enum class, and then each value needs to specify its data next to its name. It is the best practice that enum values should always be immutable, so their state should never change.
import java.math.BigDecimal
enum class PaymentOption(val commission: BigDecimal) {
CASH(BigDecimal.ONE),
CARD(BigDecimal.TEN),
TRANSFER(BigDecimal.ZERO)
}
fun main() {
println(PaymentOption.CARD.commission) // 10
println(PaymentOption.TRANSFER.commission) // 0
val paymentOption: PaymentOption =
PaymentOption.entries.random()
println(paymentOption.commission) // 0, 1 or 10
}
Enum classes with custom methods
Kotlin enums can have abstract methods whose implementations are item-specific. When we define them, the enum class itself needs to define an abstract method, and each item must override it:
enum class PaymentOption {
CASH {
override fun startPayment(
transaction: Transaction
) {
showCashPaymentInfo(transaction)
}
},
CARD {
override fun startPayment(
transaction: Transaction
) {
moveToCardPaymentPage(transaction)
}
},
TRANSFER {
override fun startPayment(
transaction: Transaction
) {
showMoneyTransferInfo()
setupPaymentWatcher(transaction)
}
};
abstract fun startPayment(transaction: Transaction)
}
This option is not popular as we generally prefer using functional primary constructor parameters[^13_1] or extension functions[^13_2].
Summary
Enum classes are a convenient way to represent a concrete set of possible values. Each value has the properties name and ordinal (position). We can get an array of all values using the values companion object function or the enumValues top-level function. We can also parse an enum value from String using the valueOf companion object function or the enumValueOf top-level function.
In the next chapter, we will talk about sealed classes, which are often treated as similar to enums but represent completely different and even more powerful abstractions. Sealed classes can form a closed hierarchy of classes, whereas enums represent only a set of constant values.
[^13_1]: Functional variables are described in the book Functional Kotlin. An example of using an enum class with functional primary constructor parameters is presented in Effective Kotlin, Item 41: Use enum to represent a list of values.
[^13_2]: Extension functions are described later in this book.
[^13_3]: entries property was introduced in Kotlin 1.9, so in projects using older versions of Kotlin you need to use values instead.
Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.
Owen has been developing software since the mid 1990s and remembers the productivity of languages such as Clipper and Borland Delphi.
Since 2001, He moved to Web, Server based Java and the Open Source revolution.
With many years of commercial Java experience, He picked up on Kotlin in early 2015.
After taking detours into Clojure and Scala, like Goldilocks, He thinks Kotlin is just right and tastes the best.
Owen enthusiastically helps Kotlin developers continue to succeed.
Nicola Corti is a Google Developer Expert for Kotlin. He has been working with the language since before version 1.0 and he is the maintainer of several open-source libraries and tools.
He's currently working as Android Infrastructure Engineer at Spotify in Stockholm, Sweden.
Furthermore, he is an active member of the developer community.
His involvement goes from speaking at international conferences about Mobile development to leading communities across Europe (GDG Pisa, KUG Hamburg, GDG Sthlm Android).
In his free time, he also loves baking, photography, and running.
Software architect with 15 years of experience, currently working on building infrastructure for AI. I think Kotlin is one of the best programming languages ever created.
Emanuele is passionate about Android and has been fascinated by it since 2010: the more he learns, the more he wishes to share what he knows with others, which is why he started maintaining his own blog.
In his current role as Senior Android Developer at Mozio, he is now focusing on Kotlin Multiplatform Mobile: he has already given a couple of talks on this topic on various occasions, so far.
Interested in everything Android and Kotlin related, including architecture patterns, TDD, functional programming and Jetpack Compose. Author of several articles about Android and Kotlin Coroutines.