Kotlin Enum Classes

Enum classes

An enum class is declared by adding enum before the class keyword.

Each enum constant is an object, and enum constants are separated with commas.

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

fun main() {
    println(Direction.NORTH)
}

Output:

NORTH

Each enum is an instance of the enum class, so it can be initialized with specific values.

enum class Color(val strRgb: String, val hexaRgb: Int) {
    RED("#f00", 0xFF0000),
    GREEN("#0f0", 0x00FF00),
    BLUE("#00f",0x0000FF ),
}

fun main() {
    println(Color.RED)
    println(Color.RED.name)
    println(Color.RED.strRgb)
    println(Color.RED.hexaRgb.toString(16))
}

Output:

RED
RED
#f00
ff0000

enum definition format

  • An enum can be defined with the enum keyword.
  • The first constant value of a defined enum is set from 0, and each following value increases by 1 from the previous constant value.
  • To set irregular values as constant values, add parentheses (()) next to the constant name and specify the desired integer constant value inside.
  • If you declare a variable with val to the right of the enum name, you can check the constant value of that enum element. The ordinal type can be specified through type declaration.

Reasons to use enum

  • It prevents instance creation and inheritance, and guarantees type safety for constant values.
  • The most basic reason to use enum classes is to implement type-safe enums.
  • Code becomes simpler and easier to read.

Anonymous classes

Enum constants can declare their own anonymous classes and methods, and can override base methods.

enum class ProtocolState {
    WAITING {
        override fun signal() = TALKING
    },
    TALKING {
        override fun signal() = WAITING
    };

    abstract fun signal(): ProtocolState
}

fun main() {
    println(ProtocolState.TALKING.signal())
    println(ProtocolState.WAITING.signal())
}

Output:

WAITING
TALKING

When defining members in an enum class, member definitions and enum constant definitions must be separated with a semicolon (;). Enum entries cannot have nested classes.

Implementing interfaces in enum classes

An enum class uses interfaces instead of inheritance.

An interface can have one interface member for all entries, or each entry inside an anonymous class can have its own interface implementation.

import java.util.function.BinaryOperator
import java.util.function.IntBinaryOperator

enum class IntArithmetics : BinaryOperator<Int>, IntBinaryOperator {
    PLUS {
        override fun apply(t: Int, u: Int): Int = t + u
    },
    TIMES {
        override fun apply(t: Int, u: Int): Int = t * u
    };

    override fun applyAsInt(t: Int, u: Int) = apply(t, u)
}

fun main() {
    val t = 2
    val u = 3

    println("PLUS($t, $u) = ${IntArithmetics.PLUS.apply(t, u)}");
    println("TIMES($t, $u) = ${IntArithmetics.TIMES.apply(t, u)}");
}

Output:

PLUS(2, 3) = 5
TIMES(2, 3) = 6

Working with enum constants

An enum class has synthetic methods that can return a list of defined enum constants and retrieve an enum constant by enum name.

The signatures of these methods are as follows.

Method Description
EnumClass.valueOf(value: String): EnumClass Returns the enum constant that matches the string passed as an argument.
EnumClass.values(): Array<EnumClass> Creates and returns an array containing all constants of the enum.

The example below retrieves a specific enum value and the list of enum class values.

fun main() {
    println(Color.valueOf("RED").name)
    println(Color.values().joinToString())
}

Output:

RED
RED, GREEN, BLUE

The valueOf() method throws IllegalArgumentException if there is no matching enum constant.

You can access enum class constants generically through the enumValues<T>() and enumValueOf<T>() functions.

enum class RGB { RED, GREEN, BLUE }

inline fun <reified T : Enum<T>> printAllValues() {
    print(enumValues<T>().joinToString { it.name })
}

fun main() {
    printAllValues<RGB>() // prints RED, GREEN, BLUE
}

Output:

RED, GREEN, BLUE

Every enum constant has properties that return its name (.name) and position (.ordinal) in the enum definition.

Method Description
val name: String Returns the enum name.
val ordinal: Int Returns the enum index.

The example below retrieves the name and position.

fun main() {
    println(Color.RED.name)
    println(Color.RED.ordinal)
}

Output:

RED
0

References