Skip to Content
Kotlin📘 Ngôn ngữ Kotlin🎯 When Expression

When Expression trong Kotlin

🎯 Mục tiêu: Nắm vững when - công cụ pattern matching mạnh mẽ của Kotlin, thay thế cho switch-case và if-else phức tạp.


💡 Khái niệm

when là phiên bản nâng cấp của switch trong Java/C, nhưng mạnh mẽ hơn nhiều:

  • Có thể match nhiều loại điều kiện
  • Có thể dùng như expression (trả về giá trị)
  • Không cần break
  • Hỗ trợ smart cast
val x = 2 when (x) { 1 -> println("Một") 2 -> println("Hai") 3 -> println("Ba") else -> println("Khác") }

📝 Cú pháp cơ bản

When với giá trị cụ thể

val day = 3 val dayName = when (day) { 1 -> "Thứ Hai" 2 -> "Thứ Ba" 3 -> "Thứ Tư" 4 -> "Thứ Năm" 5 -> "Thứ Sáu" 6 -> "Thứ Bảy" 7 -> "Chủ Nhật" else -> "Không hợp lệ" } println(dayName) // Thứ Tư

Nhiều giá trị trong một branch

val char = 'a' val type = when (char) { 'a', 'e', 'i', 'o', 'u' -> "Nguyên âm" in 'a'..'z' -> "Phụ âm" in 'A'..'Z' -> "Chữ hoa" else -> "Khác" }

When với ranges

val score = 85 val grade = when (score) { in 90..100 -> "A" in 80 until 90 -> "B" in 70 until 80 -> "C" in 60 until 70 -> "D" in 0 until 60 -> "F" else -> "Invalid" }

⭐ When as Expression

val x = 3 val result = when (x) { 1 -> "One" 2 -> "Two" else -> "Many" } // Với block val description = when (x) { 1 -> { println("X is one") "Single" } 2 -> { println("X is two") "Double" } else -> { println("X is something else") "Multiple" } }

[!TIP] Khi dùng when as expression, phải có else (trừ khi compiler chứng minh được tất cả cases đã được cover).


🔍 When không có argument

Khi không có argument, when hoạt động như chuỗi if-else:

val age = 25 val hasLicense = true val canDrive = when { age < 18 -> "Chưa đủ tuổi" !hasLicense -> "Chưa có bằng lái" else -> "Được lái xe" }

So sánh với if-else

// if-else val result = if (x > 0) { "Positive" } else if (x < 0) { "Negative" } else { "Zero" } // when (rõ ràng hơn) val result = when { x > 0 -> "Positive" x < 0 -> "Negative" else -> "Zero" }

🎯 When với Type Checking (is)

fun describe(obj: Any): String = when (obj) { is Int -> "Integer: ${obj * 2}" // Smart cast! is String -> "String length: ${obj.length}" is Boolean -> if (obj) "True" else "False" is List<*> -> "List of ${obj.size} items" else -> "Unknown: ${obj::class.simpleName}" } fun main() { println(describe(42)) // Integer: 84 println(describe("Hello")) // String length: 5 println(describe(true)) // True println(describe(listOf(1,2))) // List of 2 items }

🔒 Exhaustive When với Sealed Class & Enum

Enum - không cần else

enum class Direction { NORTH, SOUTH, EAST, WEST } fun move(direction: Direction): String = when (direction) { Direction.NORTH -> "Đi lên" Direction.SOUTH -> "Đi xuống" Direction.EAST -> "Đi phải" Direction.WEST -> "Đi trái" // Không cần else vì đã cover hết }

Sealed class - không cần else

sealed class Result { data class Success(val data: String) : Result() data class Error(val message: String) : Result() object Loading : Result() } fun handleResult(result: Result): String = when (result) { is Result.Success -> "Data: ${result.data}" is Result.Error -> "Error: ${result.message}" Result.Loading -> "Loading..." // Không cần else! }

[!NOTE] Với sealed class và enum, compiler biết tất cả subclasses nên không cần else. Nếu thêm subclass mới, compiler sẽ báo lỗi ở những chỗ chưa xử lý.


🛠️ Thực hành

Bài tập 1: Máy tính đơn giản

fun main() { val a = 10 val b = 3 val operator = "/" // TODO: Tính kết quả dựa trên operator }

Lời giải:

fun main() { val a = 10.0 val b = 3.0 val operator = "/" val result = when (operator) { "+" -> a + b "-" -> a - b "*" -> a * b "/" -> if (b != 0.0) a / b else Double.NaN "%" -> a % b else -> Double.NaN } println("$a $operator $b = $result") }

Bài tập 2: Phân loại BMI

fun main() { val bmi = 23.5 // TODO: Phân loại theo BMI: // < 18.5: Thiếu cân // 18.5-24.9: Bình thường // 25-29.9: Thừa cân // >= 30: Béo phì }

Lời giải:

fun main() { val bmi = 23.5 val category = when { bmi < 18.5 -> "Thiếu cân" bmi < 25.0 -> "Bình thường" bmi < 30.0 -> "Thừa cân" else -> "Béo phì" } println("BMI: $bmi$category") }

Bài tập 3: Mô tả kiểu dữ liệu

fun main() { val items = listOf(42, "Hello", 3.14, true, null, listOf(1, 2)) // TODO: In mô tả cho mỗi item }

Lời giải:

fun main() { val items: List<Any?> = listOf(42, "Hello", 3.14, true, null, listOf(1, 2)) for (item in items) { val description = when (item) { null -> "Null value" is Int -> "Integer: $item (doubled: ${item * 2})" is String -> "String: \"$item\" (length: ${item.length})" is Double -> "Double: ${"%.2f".format(item)}" is Boolean -> "Boolean: ${if (item) "Yes" else "No"}" is List<*> -> "List with ${item.size} elements" else -> "Unknown type" } println(description) } }

📱 Trong Android

// Xử lý navigation when (menuItemId) { R.id.nav_home -> navController.navigate(R.id.homeFragment) R.id.nav_profile -> navController.navigate(R.id.profileFragment) R.id.nav_settings -> navController.navigate(R.id.settingsFragment) } // Xử lý API response when (response) { is NetworkResult.Success -> showData(response.data) is NetworkResult.Error -> showError(response.message) is NetworkResult.Loading -> showLoading() } // View click handling view.setOnClickListener { v -> when (v.id) { R.id.btnSubmit -> submitForm() R.id.btnCancel -> cancel() R.id.btnReset -> resetForm() } }

⚠️ Lưu ý quan trọng

[!WARNING] Không có fall-through như switch trong Java:

// Kotlin - mỗi branch độc lập when (x) { 1 -> println("One") // Chỉ chạy khi x == 1 2 -> println("Two") // Chỉ chạy khi x == 2 } // Nếu muốn nhiều case cùng xử lý: when (x) { 1, 2 -> println("One or Two") }

[!CAUTION] Thứ tự các branch quan trọng:

val x = 5 // ❌ Sai - case cụ thể bị che when (x) { in 1..10 -> "1-10" // Luôn match trước! 5 -> "Five" // Không bao giờ chạy else -> "Other" } // ✅ Đúng - case cụ thể trước when (x) { 5 -> "Five" in 1..10 -> "1-10" else -> "Other" }

✅ Checklist - Tự kiểm tra

Sau bài học này, bạn có thể:

  • Sử dụng when với giá trị cụ thể
  • Sử dụng when với ranges (in 1..10)
  • Sử dụng when với type checking (is)
  • Sử dụng when không có argument
  • Hiểu exhaustive when với sealed class/enum
  • Biết when luôn cần else khi dùng làm expression (trừ sealed/enum)

Tiếp theo: Vòng lặp for

Last updated on