Skip to Content
Kotlin📘 Ngôn ngữ Kotlinλ Functional (SAM) Interfaces

Functional (SAM) Interfaces trong Kotlin

🎯 Mục tiêu: Hiểu Functional Interface (SAM interface) và SAM Conversions - cách Kotlin cho phép dùng lambda thay cho interface với một method.


💡 Functional Interface là gì?

Functional Interface (hay SAM - Single Abstract Method) là interface chỉ có một phương thức abstract duy nhất.

Trong Kotlin, khai báo với fun interface:

fun interface IntPredicate { fun accept(i: Int): Boolean }

Tại sao “functional”?

Vì nó đại diện cho một chức năng (function) duy nhất, nên có thể thay thế bằng lambda:

// Cách truyền thống - verbose val isEven = object : IntPredicate { override fun accept(i: Int): Boolean { return i % 2 == 0 } } // SAM Conversion - concise! val isEvenLambda = IntPredicate { it % 2 == 0 } fun main() { println(isEven.accept(4)) // true println(isEvenLambda.accept(4)) // true }

🔄 SAM Conversions

SAM Conversion cho phép Kotlin tự động convert lambda thành instance của functional interface:

fun interface Transformer<T, R> { fun transform(input: T): R } fun main() { // Các cách tạo instance tương đương: // 1. Anonymous object (verbose) val toUpperCase1 = object : Transformer<String, String> { override fun transform(input: String) = input.uppercase() } // 2. SAM với explicit parameter val toUpperCase2 = Transformer<String, String> { input -> input.uppercase() } // 3. SAM với it (cleanest) val toUpperCase3 = Transformer<String, String> { it.uppercase() } println(toUpperCase1.transform("hello")) // HELLO println(toUpperCase2.transform("hello")) // HELLO println(toUpperCase3.transform("hello")) // HELLO }

📝 Khai báo fun interface

Cú pháp

fun interface Runnable { fun run() } fun interface Consumer<T> { fun consume(item: T) } fun interface Mapper<T, R> { fun map(input: T): R } fun interface BiFunction<T, U, R> { fun apply(first: T, second: U): R }

Quy tắc

⚠️

fun interface chỉ có 1 abstract method:

// ✅ OK fun interface Valid { fun doSomething() } // ❌ Lỗi compile - nhiều hơn 1 abstract method fun interface Invalid { fun method1() fun method2() } // ✅ OK - có thể có default methods fun interface AlsoValid { fun doSomething() fun defaultMethod() = println("Default") // Không tính là abstract }

🎯 Sử dụng với Functions

fun interface IntOperation { fun execute(n: Int): Int } fun processNumber(n: Int, operation: IntOperation): Int { return operation.execute(n) } fun main() { // Truyền lambda trực tiếp nhờ SAM conversion val result1 = processNumber(5) { it * 2 } val result2 = processNumber(5) { it + 10 } val result3 = processNumber(5) { it * it } println(result1) // 10 println(result2) // 15 println(result3) // 25 }

Callback Pattern

fun interface OnCompletionListener { fun onComplete(result: String) } class DataLoader { fun loadData(callback: OnCompletionListener) { Thread.sleep(1000) // Simulate loading callback.onComplete("Data loaded successfully") } } fun main() { val loader = DataLoader() // SAM conversion - clean callback syntax loader.loadData { result -> println("Callback received: $result") } }

☕ Java Interoperability

Kotlin tự động áp dụng SAM conversion cho Java interfaces có một abstract method:

// Java interface public interface OnClickListener { void onClick(View view); } public class Button { public void setOnClickListener(OnClickListener listener) { // ... } }
// Kotlin sử dụng val button = Button() // Java style (verbose) button.setOnClickListener(object : OnClickListener { override fun onClick(view: View) { println("Clicked!") } }) // SAM conversion (concise) button.setOnClickListener { view -> println("Clicked!") } // Trailing lambda syntax button.setOnClickListener { println("Clicked!") }

Common Java SAM Interfaces

Java InterfaceKotlin Lambda
Runnable{ println("Running") }
Callable<T>{ computeValue() }
Comparator<T>{ a, b -> a - b }
OnClickListener{ view -> handle(view) }
Predicate<T>{ it > 0 }
Consumer<T>{ println(it) }
Function<T, R>{ it.toString() }

🆚 fun interface vs typealias

Cả hai có thể đại diện cho function:

// Approach 1: Functional Interface fun interface Validator { fun validate(input: String): Boolean } // Approach 2: Type Alias typealias ValidatorAlias = (String) -> Boolean

So sánh

Featurefun interfacetypealias
Tạo kiểu mới✅ Yes❌ No (chỉ alias)
Có thể extend✅ Yes❌ No
Default methods✅ Yes❌ No
Java interop✅ Great❌ Limited
PerformanceCó thể tạo wrapperPure function
Type safetyStrongerWeaker

Khi nào dùng gì?

// ✅ Dùng fun interface khi: // - Cần tương thích với Java // - Muốn kiểu dữ liệu riêng biệt // - Cần default methods // - Xây dựng API library fun interface NetworkCallback<T> { fun onResult(data: T) fun onError(error: Throwable) = println("Error: ${error.message}") // Default } // ✅ Dùng typealias khi: // - Chỉ cần function đơn giản // - Internal code, không expose API // - Performance critical // - Kotlin-only codebase typealias Predicate<T> = (T) -> Boolean typealias Mapper<T, R> = (T) -> R typealias Action = () -> Unit

🛠️ Thực hành

Bài tập: Tạo event system với SAM interfaces

// TODO: Tạo: // - fun interface EventHandler<T> // - class EventBus với register và emit

Lời giải:

fun interface EventHandler<T> { fun handle(event: T) } class EventBus<T> { private val handlers = mutableListOf<EventHandler<T>>() fun register(handler: EventHandler<T>) { handlers.add(handler) } // SAM-friendly register with lambda fun onEvent(handler: (T) -> Unit) { handlers.add(EventHandler { handler(it) }) } fun emit(event: T) { handlers.forEach { it.handle(event) } } fun clear() = handlers.clear() } // Usage data class UserCreatedEvent(val userId: String, val userName: String) fun main() { val userEvents = EventBus<UserCreatedEvent>() // Register với SAM conversion userEvents.register { event -> println("Handler 1: User created - ${event.userName}") } userEvents.onEvent { event -> println("Handler 2: Sending welcome email to ${event.userId}") } // Emit event userEvents.emit(UserCreatedEvent("user-123", "Alice")) // Handler 1: User created - Alice // Handler 2: Sending welcome email to user-123 }

📱 Trong Android

// Custom callback interface fun interface OnItemSelectedListener<T> { fun onSelected(item: T, position: Int) } class ItemAdapter<T>( private val items: List<T>, private val listener: OnItemSelectedListener<T> ) : RecyclerView.Adapter<ItemViewHolder>() { override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { holder.itemView.setOnClickListener { listener.onSelected(items[position], position) } } } // Usage với SAM conversion val adapter = ItemAdapter(users) { user, position -> println("Selected: ${user.name} at $position") } // Compose-style callbacks fun interface OnClick { fun onClick() } @Composable fun Button(text: String, onClick: OnClick) { // ... } // SAM in Compose Button("Click me") { println("Clicked!") }

⚠️ Lưu ý quan trọng

💡

SAM conversion chỉ hoạt động khi:

  1. Interface là fun interface (Kotlin) hoặc SAM interface (Java)
  2. Có đúng 1 abstract method
  3. Lambda được truyền trực tiếp nơi interface được expect
⚠️

Không dùng cho Kotlin interfaces thường:

// ❌ Không phải fun interface - SAM không hoạt động interface RegularInterface { fun method() } // Phải dùng object expression val impl = object : RegularInterface { override fun method() = println("Hello") } // ✅ Dùng fun interface fun interface FunctionalInterface { fun method() } val impl2 = FunctionalInterface { println("Hello") } // ✅ SAM works

✅ Checklist - Tự kiểm tra

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

  • Hiểu Functional Interface (SAM) là gì
  • Khai báo fun interface trong Kotlin
  • Sử dụng SAM conversion với lambda
  • Áp dụng SAM cho Java interfaces
  • Phân biệt fun interface vs typealias
  • Biết khi nào dùng functional interface

Tiếp theo: Higher-Order Functions

Last updated on