kotlinbeginner

Enum Classes — Advanced Patterns

Use Kotlin enum classes with properties, methods, interfaces, and companion utilities.

kotlin
// Basic enum with properties
enum class HttpStatus(val code: Int, val description: String) {
    OK(200, "Success"),
    CREATED(201, "Created"),
    BAD_REQUEST(400, "Bad Request"),
    UNAUTHORIZED(401, "Unauthorized"),
    NOT_FOUND(404, "Not Found"),
    INTERNAL_ERROR(500, "Internal Server Error");

    val isSuccess get() = code in 200..299
    val isClientError get() = code in 400..499
    val isServerError get() = code in 500..599

    companion object {
        fun fromCode(code: Int): HttpStatus? =
            entries.find { it.code == code }
    }
}

// Enum implementing interface
interface Printable {
    fun display(): String
}

enum class Planet(
    val mass: Double,     // kg
    val radius: Double    // meters
) : Printable {
    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6);

    val surfaceGravity get() = G * mass / (radius * radius)
    fun surfaceWeight(otherMass: Double) = otherMass * surfaceGravity

    override fun display() = "$name (gravity: ${"%,.2f".format(surfaceGravity)} m/s²)"

    companion object {
        const val G = 6.67300E-11
    }
}

// Enum with abstract method
enum class Operation {
    ADD {
        override fun apply(a: Double, b: Double) = a + b
        override val symbol = "+"
    },
    SUBTRACT {
        override fun apply(a: Double, b: Double) = a - b
        override val symbol = "-"
    },
    MULTIPLY {
        override fun apply(a: Double, b: Double) = a * b
        override val symbol = "×"
    },
    DIVIDE {
        override fun apply(a: Double, b: Double) = if (b != 0.0) a / b else Double.NaN
        override val symbol = "÷"
    };

    abstract fun apply(a: Double, b: Double): Double
    abstract val symbol: String
}

fun main() {
    // HttpStatus
    val status = HttpStatus.NOT_FOUND
    println("${status.code}: ${status.description} (client error: ${status.isClientError})")

    val found = HttpStatus.fromCode(200)
    println("Code 200: $found")

    // Iterate
    HttpStatus.entries
        .filter { it.isSuccess }
        .forEach { println("  ${it.code} ${it.name}") }

    // Planet
    println("\n--- Planets ---")
    val earthWeight = 75.0 // kg
    Planet.entries.forEach { planet ->
        println("${planet.display()} — Weight: ${"%,.1f".format(planet.surfaceWeight(earthWeight))} N")
    }

    // Operation
    println("\n--- Calculator ---")
    Operation.entries.forEach { op ->
        println("10 ${op.symbol} 3 = ${op.apply(10.0, 3.0)}")
    }

    // when exhaustive
    fun describe(status: HttpStatus): String = when (status) {
        HttpStatus.OK, HttpStatus.CREATED -> "Success!"
        HttpStatus.BAD_REQUEST -> "Check your request"
        HttpStatus.UNAUTHORIZED -> "Please log in"
        HttpStatus.NOT_FOUND -> "Resource not found"
        HttpStatus.INTERNAL_ERROR -> "Server error"
    }
    println(describe(HttpStatus.OK))
}

Use Cases

  • Type-safe constant sets with behavior
  • HTTP status code management
  • State and operation enumerations

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.