Enum classes in Kotlin
This is a chapter from the book Kotlin Essentials. You can find it on LeanPub or Amazon. It is also available as a course.
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.
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 thevalues
function, that returns an array of elements3.valueOf
function, which parses a string into a value matching its name (this is case-sensitive) or throws an exception.
Instead of these methods, we can also use the top-level enumValues
and enumValueOf
functions.
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).
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.
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.
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:
This option is not popular as we generally prefer using functional primary constructor parameters1 or extension functions2.
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.
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.
Extension functions are described later in this book.
entries
property was introduced in Kotlin 1.9, so in projects using older versions of Kotlin you need to use values
instead.