Kotlin Enums

Type-safe constants and enumerated values in Kotlin

🏷️ What are Kotlin Enums?

Enums in Kotlin represent a fixed set of constants in a type-safe way. They can have properties, methods, and implement interfaces, making them more powerful than simple constants while ensuring compile-time safety and preventing invalid values.


// Simple enum example
enum class Direction {
    NORTH, SOUTH, EAST, WEST
}
                                    

Enum Features

🔒

Type Safety

Compile-time constant validation

enum class Status { ACTIVE, INACTIVE }
// Only valid Status values allowed
🏷️

Properties

Each constant can have properties

enum class Color(val hex: String) {
    RED("#FF0000")
}
⚙️

Methods

Enums can have methods

enum class Operation {
    ADD;
    fun calculate(a: Int, b: Int) = a + b
}
🔄

Built-in Methods

name, ordinal, values(), valueOf()

Direction.NORTH.name // "NORTH"
Direction.NORTH.ordinal // 0

🔹 Basic Enum Declaration

Here's how to create and use simple enums:

enum class Priority {
    LOW, MEDIUM, HIGH, URGENT
}

enum class TaskStatus {
    TODO, IN_PROGRESS, DONE, CANCELLED
}

fun main() {
    val taskPriority = Priority.HIGH
    val status = TaskStatus.IN_PROGRESS
    
    println("Task priority: $taskPriority")
    println("Task status: $status")
    
    // Using built-in properties
    println("Priority name: ${taskPriority.name}")
    println("Priority ordinal: ${taskPriority.ordinal}")
    
    // Get all enum values
    println("All priorities:")
    Priority.values().forEach { priority ->
        println("  ${priority.ordinal}: ${priority.name}")
    }
    
    // Convert string to enum
    val priorityFromString = Priority.valueOf("MEDIUM")
    println("Priority from string: $priorityFromString")
}

Output:

Task priority: HIGH
Task status: IN_PROGRESS
Priority name: HIGH
Priority ordinal: 2
All priorities:
0: LOW
1: MEDIUM
2: HIGH
3: URGENT
Priority from string: MEDIUM

🔹 Enums with Properties

Enums can have properties and custom constructors:

enum class Planet(val mass: Double, val radius: Double) {
    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6);
    
    // Calculated property
    val surfaceGravity: Double
        get() = G * mass / (radius * radius)
    
    fun surfaceWeight(mass: Double): Double {
        return mass * surfaceGravity
    }
    
    companion object {
        private const val G = 6.67300E-11
    }
}

fun main() {
    val earthWeight = 75.0 // kg
    
    println("Weight on different planets:")
    Planet.values().forEach { planet ->
        val weight = planet.surfaceWeight(earthWeight)
        println("${planet.name}: ${String.format("%.2f", weight)} kg")
    }
    
    println("\nPlanet details:")
    println("Earth mass: ${Planet.EARTH.mass}")
    println("Earth radius: ${Planet.EARTH.radius}")
    println("Earth surface gravity: ${String.format("%.2f", Planet.EARTH.surfaceGravity)}")
}

Output:

Weight on different planets:
MERCURY: 28.24 kg
VENUS: 67.70 kg
EARTH: 75.00 kg
MARS: 28.39 kg

Planet details:
Earth mass: 5.976E24
Earth radius: 6378140.0
Earth surface gravity: 9.80

🔹 Enums with Methods

Enums can implement interfaces and have methods:

interface Executable {
    fun execute(a: Int, b: Int): Int
}

enum class MathOperation : Executable {
    ADD {
        override fun execute(a: Int, b: Int) = a + b
    },
    SUBTRACT {
        override fun execute(a: Int, b: Int) = a - b
    },
    MULTIPLY {
        override fun execute(a: Int, b: Int) = a * b
    },
    DIVIDE {
        override fun execute(a: Int, b: Int) = if (b != 0) a / b else 0
    };
    
    fun getSymbol(): String {
        return when (this) {
            ADD -> "+"
            SUBTRACT -> "-"
            MULTIPLY -> "*"
            DIVIDE -> "/"
        }
    }
}

class Calculator {
    fun calculate(operation: MathOperation, a: Int, b: Int): String {
        val result = operation.execute(a, b)
        val symbol = operation.getSymbol()
        return "$a $symbol $b = $result"
    }
}

fun main() {
    val calculator = Calculator()
    val a = 15
    val b = 3
    
    println("Calculator operations:")
    MathOperation.values().forEach { operation ->
        println(calculator.calculate(operation, a, b))
    }
    
    // Using specific operations
    println("\nSpecific calculations:")
    println("Addition: ${MathOperation.ADD.execute(10, 5)}")
    println("Division: ${MathOperation.DIVIDE.execute(20, 4)}")
}

Output:

Calculator operations:
15 + 3 = 18
15 - 3 = 12
15 * 3 = 45
15 / 3 = 5

Specific calculations:
Addition: 15
Division: 5

🔹 Enums in When Expressions

Enums work perfectly with when expressions for exhaustive checking:

enum class HttpStatus(val code: Int, val message: String) {
    OK(200, "OK"),
    NOT_FOUND(404, "Not Found"),
    INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
    BAD_REQUEST(400, "Bad Request"),
    UNAUTHORIZED(401, "Unauthorized")
}

fun handleHttpResponse(status: HttpStatus): String {
    return when (status) {
        HttpStatus.OK -> "✅ Request successful"
        HttpStatus.NOT_FOUND -> "❌ Resource not found"
        HttpStatus.BAD_REQUEST -> "⚠️ Invalid request"
        HttpStatus.UNAUTHORIZED -> "🔒 Authentication required"
        HttpStatus.INTERNAL_SERVER_ERROR -> "💥 Server error occurred"
        // No else clause needed - exhaustive!
    }
}

fun getStatusCategory(status: HttpStatus): String {
    return when (status.code) {
        in 200..299 -> "Success"
        in 400..499 -> "Client Error"
        in 500..599 -> "Server Error"
        else -> "Unknown"
    }
}

fun main() {
    val responses = listOf(
        HttpStatus.OK,
        HttpStatus.NOT_FOUND,
        HttpStatus.INTERNAL_SERVER_ERROR,
        HttpStatus.UNAUTHORIZED
    )
    
    println("HTTP Response Handling:")
    responses.forEach { status ->
        println("${status.code} ${status.message}")
        println("  ${handleHttpResponse(status)}")
        println("  Category: ${getStatusCategory(status)}")
        println()
    }
}

Output:

HTTP Response Handling:
200 OK
✅ Request successful
Category: Success

404 Not Found
❌ Resource not found
Category: Client Error

500 Internal Server Error
💥 Server error occurred
Category: Server Error

🔹 Advanced Enum Features

Enums with companion objects and extension functions:

enum class FileType(val extension: String, val mimeType: String) {
    PDF("pdf", "application/pdf"),
    JPEG("jpg", "image/jpeg"),
    PNG("png", "image/png"),
    TXT("txt", "text/plain"),
    JSON("json", "application/json");
    
    companion object {
        fun fromExtension(ext: String): FileType? {
            return values().find { it.extension.equals(ext, ignoreCase = true) }
        }
        
        fun getImageTypes(): List<FileType> {
            return values().filter { it.mimeType.startsWith("image/") }
        }
    }
    
    fun isImage(): Boolean = mimeType.startsWith("image/")
    
    fun getDescription(): String {
        return when (this) {
            PDF -> "Portable Document Format"
            JPEG -> "JPEG Image"
            PNG -> "PNG Image"
            TXT -> "Plain Text"
            JSON -> "JSON Data"
        }
    }
}

// Extension function
fun FileType.getMaxSize(): Long {
    return when (this) {
        FileType.PDF -> 10_000_000L // 10MB
        FileType.JPEG, FileType.PNG -> 5_000_000L // 5MB
        FileType.TXT -> 1_000_000L // 1MB
        FileType.JSON -> 2_000_000L // 2MB
    }
}

fun main() {
    // Using companion object methods
    val pdfType = FileType.fromExtension("PDF")
    println("PDF type: $pdfType")
    
    val imageTypes = FileType.getImageTypes()
    println("Image types: ${imageTypes.map { it.name }}")
    
    // Using instance methods
    println("\nFile type details:")
    FileType.values().forEach { type ->
        println("${type.name}:")
        println("  Extension: .${type.extension}")
        println("  MIME: ${type.mimeType}")
        println("  Description: ${type.getDescription()}")
        println("  Is Image: ${type.isImage()}")
        println("  Max Size: ${type.getMaxSize() / 1_000_000}MB")
        println()
    }
}

Output:

PDF type: PDF
Image types: [JPEG, PNG]

File type details:
PDF:
Extension: .pdf
MIME: application/pdf
Description: Portable Document Format
Is Image: false
Max Size: 10MB

🧠 Test Your Knowledge

What property gives you the position of an enum constant?