Higher-Order Functions trong Kotlin
🎯 Mục tiêu: Hiểu Higher-Order Functions (HOF) - hàm nhận hàm làm tham số hoặc trả về hàm.
💡 Khái niệm
Higher-Order Function là hàm có một trong hai đặc điểm:
- Nhận một hàm làm tham số
- Trả về một hàm
// HOF nhận function làm tham số
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
fun main() {
val sum = calculate(5, 3) { a, b -> a + b }
println(sum) // 8
}📝 Function Types
Cú pháp
(ParameterTypes) -> ReturnTypeVí dụ
val sum: (Int, Int) -> Int = { a, b -> a + b }
val greet: (String) -> Unit = { println("Hello, $it") }
val isEven: (Int) -> Boolean = { it % 2 == 0 }
val noParams: () -> String = { "Hello!" }⭐ Định nghĩa HOF
Nhận function làm tham số
fun repeat(times: Int, action: (Int) -> Unit) {
for (i in 0 until times) {
action(i)
}
}
fun main() {
repeat(3) { index ->
println("Iteration $index")
}
}Trả về function
fun createMultiplier(factor: Int): (Int) -> Int {
return { number -> number * factor }
}
fun main() {
val double = createMultiplier(2)
val triple = createMultiplier(3)
println(double(5)) // 10
println(triple(5)) // 15
}🔗 Built-in HOF cho Collections
map
val numbers = listOf(1, 2, 3, 4, 5)
val squared = numbers.map { it * it }
println(squared) // [1, 4, 9, 16, 25]filter
val numbers = listOf(1, 2, 3, 4, 5, 6)
val even = numbers.filter { it % 2 == 0 }
println(even) // [2, 4, 6]reduce / fold
val numbers = listOf(1, 2, 3, 4, 5)
val sum = numbers.reduce { acc, n -> acc + n } // 15
val product = numbers.fold(1) { acc, n -> acc * n } // 120find / first / last
val numbers = listOf(1, 2, 3, 4, 5)
val firstEven = numbers.find { it % 2 == 0 } // 2
val firstOrNull = numbers.firstOrNull { it > 10 } // nullany / all / none
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.any { it > 3 }) // true - có ít nhất 1
println(numbers.all { it > 0 }) // true - tất cả
println(numbers.none { it < 0 }) // true - không cógroupBy / partition
val numbers = listOf(1, 2, 3, 4, 5, 6)
val grouped = numbers.groupBy { if (it % 2 == 0) "even" else "odd" }
println(grouped) // {odd=[1, 3, 5], even=[2, 4, 6]}
val (even, odd) = numbers.partition { it % 2 == 0 }
println(even) // [2, 4, 6]
println(odd) // [1, 3, 5]🔄 Chaining HOFs
data class User(val name: String, val age: Int, val city: String)
val users = listOf(
User("Alice", 25, "Hanoi"),
User("Bob", 30, "HCMC"),
User("Charlie", 20, "Hanoi"),
User("David", 35, "Danang")
)
val result = users
.filter { it.age >= 25 }
.sortedBy { it.name }
.map { "${it.name} (${it.city})" }
.joinToString(", ")
println(result) // Alice (Hanoi), Bob (HCMC), David (Danang)🛠️ Thực hành
Bài tập 1: Tạo custom HOF
fun main() {
// TODO: Viết hàm doIf(condition, action)
// thực thi action nếu condition đúng
}Lời giải:
inline fun doIf(condition: Boolean, action: () -> Unit) {
if (condition) action()
}
fun main() {
val age = 20
doIf(age >= 18) {
println("Đủ tuổi")
}
doIf(age < 18) {
println("Chưa đủ tuổi") // Không in
}
}Bài tập 2: Retry mechanism
fun main() {
// TODO: Viết hàm retry(times, action)
// thử lại action nếu throw exception
}Lời giải:
inline fun <T> retry(times: Int, action: () -> T): T? {
var lastException: Exception? = null
repeat(times) { attempt ->
try {
return action()
} catch (e: Exception) {
lastException = e
println("Attempt ${attempt + 1} failed: ${e.message}")
}
}
return null
}
fun main() {
var callCount = 0
val result = retry(3) {
callCount++
if (callCount < 3) throw Exception("Failed")
"Success!"
}
println(result) // Success! (sau 2 lần thất bại)
}Bài tập 3: Pipeline function
fun main() {
// TODO: Tạo pipeline xử lý string
}Lời giải:
fun pipeline(
input: String,
vararg transforms: (String) -> String
): String {
return transforms.fold(input) { acc, transform -> transform(acc) }
}
fun main() {
val result = pipeline(
" hello world ",
{ it.trim() },
{ it.uppercase() },
{ it.replace(" ", "_") }
)
println(result) // HELLO_WORLD
}📱 Trong Android
// Custom view extension
inline fun View.doOnClick(crossinline action: () -> Unit) {
setOnClickListener { action() }
}
// Usage
button.doOnClick {
navigateToNext()
}
// LiveData transformation
val users: LiveData<List<User>> = repository.getUsers()
val activeUsers: LiveData<List<User>> = users.map { list ->
list.filter { it.isActive }
}
// Network call wrapper
suspend fun <T> safeApiCall(
apiCall: suspend () -> T
): Result<T> {
return try {
Result.success(apiCall())
} catch (e: Exception) {
Result.failure(e)
}
}⚠️ Lưu ý quan trọng
[!TIP] Dùng
inlineđể tối ưu performance:// Không inline - tạo object mới cho mỗi lambda fun doSomething(action: () -> Unit) { action() } // Inline - không tạo object, copy code trực tiếp inline fun doSomething(action: () -> Unit) { action() }
✅ Checklist - Tự kiểm tra
Sau bài học này, bạn có thể:
- Hiểu function types:
(Params) -> Return - Định nghĩa HOF nhận function làm tham số
- Định nghĩa HOF trả về function
- Sử dụng thành thạo
map,filter,reduce,fold - Chain nhiều HOF lại với nhau
- Hiểu khi nào dùng
inline
Tiếp theo: Scope Functions
Last updated on