Kotlin Enum Classes
Introduction
Enum classes are a special type of class in Kotlin used to represent a fixed set of constants. Think of them as a way to define a collection of named values that represent distinct states, options, or modes in your application.
Unlike regular classes, enums restrict object creation to the set of predefined constants, making them perfect for representing concepts like days of the week, directions, status codes, or any scenario where you need a limited set of possible values.
In this tutorial, we'll explore how Kotlin's enum classes work, how they differ from enums in other languages, and how to leverage their unique features.
Basic Enum Class Syntax
Let's start with a simple enum class definition:
enum class Direction {
NORTH, EAST, SOUTH, WEST
}
This creates an enum with four possible values. You can use it like this:
fun navigate(direction: Direction) {
when(direction) {
Direction.NORTH -> println("Going north")
Direction.EAST -> println("Going east")
Direction.SOUTH -> println("Going south")
Direction.WEST -> println("Going west")
}
}
fun main() {
navigate(Direction.NORTH) // Output: Going north
// You can also use variables to store enum values
val currentDirection = Direction.EAST
navigate(currentDirection) // Output: Going east
}
Enum Properties and Methods
Unlike enums in some other languages, Kotlin enum constants are actual instances of the enum class. This means they can have properties and methods:
enum class Day(val abbreviation: String, val isWeekend: Boolean) {
MONDAY("Mon", false),
TUESDAY("Tue", false),
WEDNESDAY("Wed", false),
THURSDAY("Thu", false),
FRIDAY("Fri", false),
SATURDAY("Sat", true),
SUNDAY("Sun", true);
fun printInfo() {
println("$name ($abbreviation) - ${if (isWeekend) "Weekend" else "Weekday"}")
}
}
fun main() {
Day.MONDAY.printInfo() // Output: MONDAY (Mon) - Weekday
Day.SUNDAY.printInfo() // Output: SUNDAY (Sun) - Weekend
// Check if a day is a weekend
println(Day.FRIDAY.isWeekend) // Output: false
println(Day.SATURDAY.isWeekend) // Output: true
}
Notice that each enum constant is created by passing the required parameters to the constructor. Also, note the semicolon after the last enum constant when adding methods.
Built-in Properties and Methods
All Kotlin enums automatically come with some useful properties and methods:
fun main() {
// name - returns the name of the enum constant
println(Direction.NORTH.name) // Output: NORTH
// ordinal - returns the position (0-based) of the enum constant
println(Direction.EAST.ordinal) // Output: 1
// values() - returns an array of all enum constants
val allDirections = Direction.values()
for (direction in allDirections) {
println(direction)
}
// Output:
// NORTH
// EAST
// SOUTH
// WEST
// valueOf() - returns the enum constant with the specified name
val south = Direction.valueOf("SOUTH")
println(south == Direction.SOUTH) // Output: true
// Will throw IllegalArgumentException if the name doesn't match any constant
try {
Direction.valueOf("NORTHEAST")
} catch (e: IllegalArgumentException) {
println("Invalid direction name!") // Output: Invalid direction name!
}
}
Using Enum Classes with When Expressions
Enum classes work particularly well with Kotlin's when
expressions, and the compiler can perform an exhaustiveness check to ensure all cases are covered:
enum class Result {
SUCCESS, ERROR, LOADING
}
fun handleResult(result: Result) {
when (result) {
Result.SUCCESS -> println("Operation completed successfully")
Result.ERROR -> println("An error occurred")
Result.LOADING -> println("Operation in progress")
// No 'else' branch needed - the compiler checks all cases are covered
}
}
fun main() {
handleResult(Result.SUCCESS) // Output: Operation completed successfully
handleResult(Result.ERROR) // Output: An error occurred
}
Implementing Interfaces in Enum Classes
Enum classes in Kotlin can implement interfaces, which can be very powerful:
interface Clickable {
fun onClick()
}
enum class Button(val label: String) : Clickable {
OK("OK") {
override fun onClick() {
println("$label button clicked: Proceeding...")
}
},
CANCEL("Cancel") {
override fun onClick() {
println("$label button clicked: Operation cancelled")
}
},
HELP("Help") {
override fun onClick() {
println("$label button clicked: Displaying help")
}
};
}
fun main() {
Button.OK.onClick() // Output: OK button clicked: Proceeding...
Button.CANCEL.onClick() // Output: Cancel button clicked: Operation cancelled
}
Enum Class with Abstract Method
You can define abstract methods in an enum class, forcing each enum constant to provide its own implementation:
enum class Operation {
ADD {
override fun apply(x: Int, y: Int): Int = x + y
},
SUBTRACT {
override fun apply(x: Int, y: Int): Int = x - y
},
MULTIPLY {
override fun apply(x: Int, y: Int): Int = x * y
},
DIVIDE {
override fun apply(x: Int, y: Int): Int = if (y != 0) x / y else throw IllegalArgumentException("Cannot divide by zero")
};
abstract fun apply(x: Int, y: Int): Int
}
fun main() {
println(Operation.ADD.apply(5, 3)) // Output: 8
println(Operation.SUBTRACT.apply(5, 3)) // Output: 2
println(Operation.MULTIPLY.apply(5, 3)) // Output: 15
println(Operation.DIVIDE.apply(6, 3)) // Output: 2
}
Real-World Example: HTTP Status Codes
Let's look at a practical example where enum classes can be very useful - representing HTTP status codes:
enum class HttpStatus(val code: Int, val message: String) {
OK(200, "OK"),
CREATED(201, "Created"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error");
companion object {
fun fromCode(code: Int): HttpStatus? {
return values().find { it.code == code }
}
}
val isSuccess: Boolean
get() = code in 200..299
val isClientError: Boolean
get() = code in 400..499
val isServerError: Boolean
get() = code in 500..599
}
fun handleResponse(status: HttpStatus) {
println("Received response with status: ${status.code} ${status.message}")
when {
status.isSuccess -> println("Request successful!")
status.isClientError -> println("Client error. Please check your request.")
status.isServerError -> println("Server error. Please try again later.")
}
}
fun main() {
val response = HttpStatus.OK
handleResponse(response)
// Output:
// Received response with status: 200 OK
// Request successful!
val errorResponse = HttpStatus.NOT_FOUND
handleResponse(errorResponse)
// Output:
// Received response with status: 404 Not Found
// Client error. Please check your request.
// We can also look up a status by its code
val unknownCode = 418
val status = HttpStatus.fromCode(unknownCode)
if (status != null) {
handleResponse(status)
} else {
println("Unknown status code: $unknownCode")
}
// Output: Unknown status code: 418
}
Summary
Kotlin enum classes are a powerful feature that goes beyond simple enumerations found in other languages. They allow you to:
- Define a fixed set of constants
- Add properties and methods to your enum and its constants
- Implement interfaces
- Define abstract methods with different implementations for each constant
- Use built-in properties and methods like
name
,ordinal
, andvalues()
- Work seamlessly with Kotlin's
when
expressions
Enum classes are ideal for representing fixed sets of related constants such as status codes, states, options, modes, or any other concept with a limited number of possible values.
Exercises
-
Create an enum class
Color
with constantsRED
,GREEN
, andBLUE
. Add RGB values as properties to each constant. -
Define an enum class
PaymentMethod
with constantsCREDIT_CARD
,DEBIT_CARD
,PAYPAL
, andBANK_TRANSFER
. Add a methodprocessPayment()
that prints different messages for each payment method. -
Implement an enum class
Planet
with constants for all planets in our solar system. Include properties for mass, radius, and surface gravity. Add a method to calculate the weight of an object on each planet. -
Create an enum class
LogLevel
with constantsDEBUG
,INFO
,WARNING
, andERROR
. Implement a system for filtering logs based on minimum log level.
Additional Resources
- Official Kotlin Documentation on Enum Classes
- Effective Java by Joshua Bloch - Chapter 6: Enums and Annotations
- Kotlin In Action - Contains detailed information about enum classes
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)