Antonello Zanini I'm a software engineer, but I prefer to call myself a technology bishop. Spreading knowledge through writing is my mission.

A complete guide to enum classes in Kotlin

Let’s look at everything you need to start dealing with Kotlin enum classes like a pro.

7 min read 2221

Kotlin Enum Classes Complete Guide

A useful feature while programming is having the ability to indicate that a variable only has a finite set of possible values. To accomplish this, most programming languages introduced the concept of enumerations.

Although enumerations usually represent just a mere named list of predefined constant values, Kotlin enums are much more than that. In fact, they are real classes, and not simple types or limited data structured.

This translates to the fact that they can have custom properties and methods, implement interfaces, use anonymous classes, and much more. Thus, Kotlin enum classes play a crucial role in the language.

Plus, employing enums makes your code more readable and less error-prone. This is why every Kotlin developer should know how to use them. So, let’s dive into enum classes and see everything you need to learn to master them.

Kotlin enum classes vs. Java enum types

In Java, enums are types. Specifically, the official documentation defines an enum type as “a special data type that enables a variable to be a set of predefined constants.” This means that the aforementioned variable must be equal to one of the predefined values. These values are constants, and represent the properties of the enum type.

Despite being a type, the Java enum declaration actually creates a class behind the scenes. Thus, Java enums can include custom methods and properties. This, in addition to the default ones automatically added by the compiler. That’s it — nothing more can be done with Java enum types.

Unlike what happens in Java, Kotlin enums are classes natively, and not only behind the scenes. This is why they are called enum classes, as opposed to Java enum types. That prevents developers from considering them as just mere collections of constants, as may happen in Java.

As we are about to see, Kotlin enums are much more than that. Not only can they use anonymous classes, but also implement interfaces, just like any other Kotlin class. So, let’s forget Java enum types and start delving into Kotlin enum classes.

Basic features of Kotlin enums

Let’s start exploring the most common features offered by Kotlin enums.

Defining enums

The most basic use case for Kotlin enum classes is to treat them as collections of constants. In this case, they are called type-safe enums and can be defined as follows:

We made a custom demo for .
No really. Click here to check it out.

enum class Day {   
    MONDAY, 
    TUESDAY,
    WEDNESDAY, 
    THURSDAY, 
    FRIDAY, 
    SATURDAY,
    SUNDAY
}

As you can see, the enum keyword is followed by the class keyword. This should prevent you from being fooled into thinking that Kotlin enums are mere types.

Then comes the enum class name. Finally, inside the body of the enum class, the possible comma-separated options called enum constants. Note that since they are constants, their names should always be in uppercase letters. This is what the simplest Kotlin enum class consists of.

Initializing enums

Kotlin enums are classes, which means that they can have one or more constructors. Thus, you can initialize enum constants by passing the values required to one of the valid constructors. This is possible because enum constants are nothing other than instances of the enum class itself.
Let’s see how this works through an example:

enum class Day(val dayOfWeek: Int) {    
    MONDAY(1), 
    TUESDAY(2),
    WEDNESDAY(3), 
    THURSDAY(4), 
    FRIDAY(5), 
    SATURDAY(6),
    SUNDAY(7)
}

This way, each enum constant is associated with the relative number of the day of the week.

Usually, the constructor-based approach is used to provide enum constants with useful information or meaningful values. On of the most common cases is to provide them with a custom printableName property. This is very useful when printing them, and can be achieved as follows:

enum class Day(val printableName: String) {    
    MONDAY("Monday"), 
    TUESDAY("Tuesday"),
    WEDNESDAY("Wednesday"), 
    THURSDAY("Thursday"), 
    FRIDAY("Friday"), 
    SATURDAY("Saturday"),
    SUNDAY("Sunday")
}

Inbuilt properties

Kotlin enum classes come with a few inbuilt properties. Just like what happens in Java, they are automatically added to each enum class by the compiler. So, you can access them in any enum class instance. Let’s see them all:

  1. ordinal
    ordinal allows you to retrieve where the current enum constant appears in the list. It is a zero-based index, which means that the first constant in the options list has value 0, the second 1, and so on. When implementing the Comparable interface, this property will be used in sorting logic.
  2. name
    name returns the name of the enum constant as a string.

Let’s see these two in action through the following example:

enum class Day(val dayOfWeek: Int) {
    MONDAY(1), 
    TUESDAY(2),
    WEDNESDAY(3), 
    THURSDAY(4), 
    FRIDAY(5), 
    SATURDAY(6),
    SUNDAY(7)
}

fun main() {    
    for (day in DAY.values())
        println("[${day.ordinal}] -> ${day.name} (${day.dayOfWeek}^ day of the week)")
}

By running this code, you would get the following result:

[0] -> MONDAY (1^ day of the week)
[1] -> TUESDAY (2^ day of the week)
[2] -> WEDNESDAY (3^ day of the week)
[3] -> THURSDAY (4^ day of the week)
[4] -> FRIDAY (5^ day of the week)
[5] -> SATURDAY (6^ day of the week)
[6] -> SUNDAY (7^ day of the week)

As you can see, the string returned by the name inbuilt property coincides with the constant itself. This does not make them very printable, and this is why adding a custom printableName property might be useful.

Also, this example highlights why adding a custom index might be required as well. This is because ordinal is a zero-based index meant to be used while programming rather than to provide informational content.

Advanced features of Kotlin enums

Now, it is time to delve into the most advanced and complicated features offered by Kotlin enum classes.

Adding custom properties and methods

Custom properties and methods can be added to enum classes, just like in any other Kotlin class. What changes is the syntax, which must follow specific rules.

In particular, methods and properties must be added below the enum constants definition, after a semicolon. Just like any other property in Kotlin, you can provide them with a default value. Plus, enum classes can have both instance and static methods:

enum class Day {
    MONDAY(1, "Monday"),
    TUESDAY(2, "Tuesday"),
    WEDNESDAY(3, "Wednesday"),
    THURSDAY(4, "Thursday"),
    FRIDAY(5, "Friday"),
    SATURDAY(6, "Saturday"),
    SUNDAY(7, "Sunday"); // end of the constants

    // custom properties with default values
    var dayOfWeek: Int? = null
    var printableName : String? = null

    constructor()

    // custom constructors
    constructor(
        dayOfWeek: Int,
        printableName: String
    ) {
        this.dayOfWeek = dayOfWeek
        this.printableName = printableName
    }

    // custom method
    fun customToString(): String {
        return "[${dayOfWeek}] -> $printableName"
    }
}

In this example, a custom constructor, two custom properties, and a custom instance method were added to the enum class. Properties and methods can be accessed through instances, which are the enum constants, with the following syntax:

// accessing the dayOfWeek property
Day.MONDAY.dayOfWeek

// accessing the customToString() method
Day.MONDAY.customToString()

Keep in mind that Kotlin does not have the concept of static methods. However, the same result can be achieved by harnessing companion objects, which are supported by Kotlin enum classes. Methods defined inside companion objects do not depend on specific instances and be accessed statically. You can add one as follows:

enum class Day {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;

    companion object {
        fun getNumberOfDays() = values().size
    }
}

Now, you can access the getNumberOfDays() method this way:

Day.getNumberOfDays()

As you can see, the method is called statically on the class and does not depend on any instance. Note that the synthetic static method values() was used while implementing it. You are going to see what it is and how to use it very soon.

Using anonymous classes to define enum constants

We can create anonymous classes to define specific enum constants. In contrast to Java, Kotlin enum classes support anonymous classes.

In particular, enum constants can be instantiated by anonymous classes. They just have to give an implementation to the abstract methods of the enum class itself. This can be achieved with the following syntax:

enum class Day {
    MONDAY {
        override fun nextDay() = TUESDAY
    },
    TUESDAY {
        override fun nextDay() = WEDNESDAY
    },
    WEDNESDAY {
        override fun nextDay() = THURSDAY
    },
    THURSDAY {
        override fun nextDay() = FRIDAY
    },
    FRIDAY {
        override fun nextDay() = SATURDAY
    },
    SATURDAY {
        override fun nextDay() = SUNDAY
    },
    SUNDAY {
        override fun nextDay() = MONDAY
    };

    abstract fun nextDay(): Day
}

As shown here, each enum constant is instantiated by declaring its own anonymous classes while overriding the required abstract method. This is just as it would happen in any other Kotlin anonymous class.

Enums can implement interfaces

Although Kotlin enum classes cannot derive from a class, enum class, or an abstract class, they can actually implement one or more interfaces.

In this case, each enum constant must provide an implementation of interface methods. This can be achieved with a common implementation, as follows:

interface IDay {
    fun firstDay(): Day
}


enum class Day: IDay {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;

    override fun firstDay(): Day {
      return MONDAY  
    } 
}

Or by using anonymous classes as showed before:

interface IDay {
    fun nextDay(): Day
}


enum class Day: IDay {
    MONDAY {
        override fun nextDay() = TUESDAY
    },
    TUESDAY {
        override fun nextDay() = WEDNESDAY
    },
    WEDNESDAY {
        override fun nextDay() = THURSDAY
    },
    THURSDAY {
        override fun nextDay() = FRIDAY
    },
    FRIDAY {
        override fun nextDay() = SATURDAY
    },
    SATURDAY {
        override fun nextDay() = SUNDAY
    },
    SUNDAY {
        override fun nextDay() = MONDAY
    };
}

In both cases, each enum constant has the IDay interface method implemented.

Enums in action

Now that you have seen both basic and advanced features, you have everything required to start using Kotlin enum classes. Let’s see them in action through the three most common use cases.

Enums and when

Enum classes are particularly useful when used with Kotlin’s when conditional statement. This is because when expressions must take each possible condition into account. In other words, they must be exhaustive.

Since enums offer a limited set of values by definition, Kotlin can use this to figure out if every condition was considered. If not, an error at compile time will be thrown. Let’s see enums in action with the when expression:

enum class Day {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

fun main (currentDay: Day) {
    when (currentDay) {
        Day.MONDAY -> work()
        Day.TUESDAY -> work()
        Day.WEDNESDAY -> work()
        Day.THURSDAY -> work()
        Day.FRIDAY -> work()
        Day.SATURDAY -> rest()
        Day.SUNDAY -> rest()
    }
}

fun work() {
    println("Working")
}

fun rest() {
    println("Resting")
}

As just shown, enums allow you to differentiate logic based on their value. They also make your code more readable and less error-prone. This is because they establish the maximum number of possible options to be considered in a when statement. This way, you cannot forget one.

Enums and Kotlin synthetic methods

Similar to the aforementioned inbuilt properties, every enum class also has synthetic methods. They are automatically added by Kotlin at compile time and represent utility functions that can be accessed statically. Let’s see the most important ones and how to use them:

  • values()
    It returns the list of all the enum constants contained within the enum class.
  • valueOf(value: String)
    It returns the enum constant whose name property matches the value string passed as a parameter. If not found, an IllegalArgumentException is thrown.

Let’s see them in action through an example:

enum class Day(val printableName: String) {
    MONDAY("Monday"),
    TUESDAY("Tuesday"),
    WEDNESDAY("Wednesday"),
    THURSDAY("Thursday"),
    FRIDAY("Friday"),
    SATURDAY("Saturday"),
    SUNDAY("Sunday")
}

fun main () {
    for (day in Day.values())        
        println(day.printableName)

   println(Day.valueOf("MONDAY").printableName)
}

When run, the following result would be printed:

Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Monday

Note that the same result can be obtained by employing the two following Kotlin global functions: enumValues<T>() and enumValueOf<T>(). They allow you to access any enum class T with a generic-based approach.

Iterating through enums

Finally, both use cases can be combined to iterate through them thanks the values() synthetic method and execute different actions based on their value with a when expression. Let’s look at an example based on this approach:

enum class Day(val printableName: String) {
    MONDAY("Monday"),
    TUESDAY("Tuesday"),
    WEDNESDAY("Wednesday"),
    THURSDAY("Thursday"),
    FRIDAY("Friday"),
    SATURDAY("Saturday"),
    SUNDAY("Sunday")
}

fun main () {
    for (day in Day.values()) {
        // common behavior
        println(day.printableName)

        // action execute based on day value
        when (day) {
            Day.MONDAY -> work()
            Day.TUESDAY -> work()
            Day.WEDNESDAY -> work()
            Day.THURSDAY -> work()
            Day.FRIDAY -> work()
            Day.SATURDAY -> rest()
            Day.SUNDAY -> rest()
        }

        // common behavior
        println("---")
    }
}

fun work() {
    println("Working")
}

fun rest() {
    println("Resting")
}

This way, custom logic can be executed based on each of the current possible values of which the enum class consists of. If launched, the snippet would return this:

Monday
Working
---
Tuesday
Working
---
Wednesday
Working
---
Thursday
Working
---
Friday
Working
---
Saturday
Resting
---
Sunday
Resting
---

Conclusion

In this article, we looked at what Kotlin enum classes are, when and how to use them, and why. As shown, Kotlin enums come with many features and offer you endless possibilities. So, simply thinking of them as a set of constants would be a mistake, as opposed to what happens in many other programming languages.

Since Kotlin enums are classes, they can have their own properties, methods, and implement interfaces. Plus, when used correctly, they can make your code clearer, more readable, and less error-prone. This is why every Kotlin developer should use them, and teaching everything required to do it properly was what this article was about.

Thanks for reading! I hope that you found this article helpful. Feel free to reach out to me with any questions, comments, or suggestions.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Antonello Zanini I'm a software engineer, but I prefer to call myself a technology bishop. Spreading knowledge through writing is my mission.

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re...
Laura Carballo
4 min read

Leave a Reply