🕵️ Kiểm tra và Ép kiểu
🎯 Mục tiêu: Nắm vững cách kiểm tra kiểu (
is), ép kiểu an toàn (as?) và cơ chế Smart Casts thông minh của Kotlin.
🕵️ Kiểm tra kiểu (is / !is)
Phần tiêu đề “🕵️ Kiểm tra kiểu (is / !is)”Dùng is để kiểm tra xem một object có phải là kiểu cụ thể hay không (tương đương instanceof trong Java).
if (obj is String) { print(obj.length)}
if (obj !is String) { // Tương đương !(obj is String) print("Not a String")}🧠 Smart Casts
Phần tiêu đề “🧠 Smart Casts”Kotlin compiler cực kỳ thông minh! Nếu bạn đã kiểm tra kiểu với is, nó sẽ tự động ép kiểu (cast) biến đó trong phạm vi tương ứng mà không cần bạn làm gì thêm.
Với if và when
Phần tiêu đề “Với if và when”fun demo(x: Any) { if (x is String) { print(x.length) // x tự động là String }}
when (x) { is Int -> print(x + 1) is String -> print(x.length + 1) is IntArray -> print(x.sum())}Với && và ||
Phần tiêu đề “Với && và ||”// Bên phải &&if (x is String && x.length > 0) { print(x.length) // x là String}
// Bên phải || (negative check)if (x !is String || x.isEmpty()) { return}Smart Casts hoạt động khi nào?
Phần tiêu đề “Smart Casts hoạt động khi nào?”Smart cast chỉ hoạt động khi compiler đảm bảo biến không thay đổi giữa lúc kiểm tra và lúc sử dụng.
- val local variables: Luôn hoạt động (trừ local delegated properties).
- val properties: Hoạt động nếu private/internal hoặc check trong cùng module.
- var local variables: Hoạt động nếu không bị thay đổi giữa check và use, không bị capture bởi lambda thay đổi nó.
- var properties: Không bao giờ hoạt động (vì code khác có thể thay đổi bất cứ lúc nào).
🔄 Ép kiểu (Type Casts)
Phần tiêu đề “🔄 Ép kiểu (Type Casts)”Unsafe Cast (as)
Phần tiêu đề “Unsafe Cast (as)”Dùng as khi bạn chắc chắn về kiểu. Nếu sai, nó sẽ ném ClassCastException.
val y = nullval x: String = y as String // ❌ Exception: null cannot be cast to non-null StringĐể cast nullable:
val x: String? = y as String? // ✅ OK, x = nullSafe Cast (as?)
Phần tiêu đề “Safe Cast (as?)”Dùng as? để tránh exception. Nếu cast thất bại, nó trả về null.
val x: String? = y as? StringĐây là cách được khuyên dùng để xử lý ép kiểu an toàn.
🧬 Generics Type Checks
Phần tiêu đề “🧬 Generics Type Checks”Do Type Erasure (xóa kiểu generic tại runtime), bạn không thể kiểm tra cụ thể generic type của một instance (trừ khi dùng inline reified).
// ❌ Lỗi biên dịch// if (list is List<String>) { ... }
// ✅ OK: Kiểm tra Star-projected typeif (list is List<*>) { // list là một List nào đó, nhưng không biết phần tử là gì}Để kiểm tra generic type thực sự, dùng Inline Functions với reified:
inline fun <reified T> isType(value: Any): Boolean { return value is T}🛠️ Thực hành
Phần tiêu đề “🛠️ Thực hành”Bài tập 1: Xử lý Any
fun process(input: Any) { // TODO: // Nếu input là String, in độ dài // Nếu input là Int, in bình phương // Nếu input là List, in số phần tử // Dùng when expression}Lời giải:
fun process(input: Any) { when (input) { is String -> println("String length: ${input.length}") is Int -> println("Square: ${input * input}") is List<*> -> println("List size: ${input.size}") else -> println("Unknown type") }}✅ Checklist
Phần tiêu đề “✅ Checklist”- Sử dụng
isđể kiểm tra kiểu - Tận dụng Smart Casts để code gọn hơn
- Luôn ưu tiên
as?thay vìas - Hiểu hạn chế của Smart Casts với
varproperties