🔄 Chuyển đổi Kiểu dữ liệu
🎯 Mục tiêu: Học cách chuyển đổi kiểu dữ liệu an toàn trong Kotlin với các method conversion và smart casts.
💡 Khái niệm
Phần tiêu đề “💡 Khái niệm”Kotlin là strongly typed - không tự động chuyển đổi kiểu (không như JavaScript). Bạn phải chuyển đổi tường minh.
val intValue: Int = 100
// ❌ Lỗi - Kotlin không implicit conversion// val longValue: Long = intValue
// ✅ Phải convert tường minhval longValue: Long = intValue.toLong()📝 Conversion Methods cho số
Phần tiêu đề “📝 Conversion Methods cho số”Các method cơ bản
Phần tiêu đề “Các method cơ bản”Mỗi kiểu số đều có các method chuyển đổi:
val number = 42
val toByte: Byte = number.toByte()val toShort: Short = number.toShort()val toInt: Int = number.toInt()val toLong: Long = number.toLong()val toFloat: Float = number.toFloat()val toDouble: Double = number.toDouble()val toChar: Char = number.toChar()Ví dụ chuyển đổi
Phần tiêu đề “Ví dụ chuyển đổi”// Int → Longval count = 1000000val bigCount = count.toLong()
// Double → Int (mất phần thập phân)val price = 99.99val roundedPrice = price.toInt() // 99
// Float ↔ Doubleval floatVal = 3.14fval doubleVal = floatVal.toDouble()🔢 Chuyển đổi String ↔ Số
Phần tiêu đề “🔢 Chuyển đổi String ↔ Số”String → Số
Phần tiêu đề “String → Số”// Cách an toàn (trả về null nếu không parse được)val str = "42"val number = str.toIntOrNull() // 42val invalid = "abc".toIntOrNull() // null
// Các kiểu khácval long = "1000000".toLongOrNull()val double = "3.14".toDoubleOrNull()val float = "3.14".toFloatOrNull()Cách không an toàn (throw exception)
Phần tiêu đề “Cách không an toàn (throw exception)”val number = "42".toInt() // 42val error = "abc".toInt() // ❌ NumberFormatException!Số → String
Phần tiêu đề “Số → String”val number = 42val str = number.toString() // "42"
// Format sốval price = 15000000val formatted = "%,d".format(price) // "15,000,000"val decimal = 3.14159val fixed = "%.2f".format(decimal) // "3.14"🎯 Smart Casts với is
Phần tiêu đề “🎯 Smart Casts với is”Kotlin tự động cast sau khi kiểm tra kiểu với is:
fun process(value: Any) { if (value is String) { // Smart cast: value đã là String ở đây println("String length: ${value.length}") }
if (value is Int) { // Smart cast: value đã là Int ở đây println("Squared: ${value * value}") }}Smart Cast với when
Phần tiêu đề “Smart Cast với when”fun describe(obj: Any): String = when (obj) { is Int -> "Integer: ${obj * 2}" is String -> "String: ${obj.uppercase()}" is Boolean -> if (obj) "True" else "False" is List<*> -> "List of ${obj.size} items" else -> "Unknown type"}Negative Smart Cast
Phần tiêu đề “Negative Smart Cast”fun processNotNull(value: Any?) { if (value !is String) { return // Exit early } // value is String from here println(value.uppercase())}⚠️ Unsafe Cast với as
Phần tiêu đề “⚠️ Unsafe Cast với as”Cast không an toàn - throw exception nếu không thành công:
val obj: Any = "Hello"
val str: String = obj as String // ✅ OK// val num: Int = obj as Int // ❌ ClassCastException!✅ Safe Cast với as?
Phần tiêu đề “✅ Safe Cast với as?”Cast an toàn - trả về null nếu không thành công:
val obj: Any = "Hello"
val str: String? = obj as? String // "Hello"val num: Int? = obj as? Int // null (không crash)🔄 Type Checking
Phần tiêu đề “🔄 Type Checking”Kiểm tra kiểu với is
Phần tiêu đề “Kiểm tra kiểu với is”val value: Any = "Kotlin"
println(value is String) // trueprintln(value is Int) // falseprintln(value !is Int) // trueKiểm tra nullable với is
Phần tiêu đề “Kiểm tra nullable với is”val nullableValue: Any? = null
println(nullableValue is String) // falseprintln(nullableValue is String?) // Không cần - dùng null checkprintln(nullableValue == null) // true📊 Generics và Type Erasure
Phần tiêu đề “📊 Generics và Type Erasure”Kotlin sử dụng type erasure - thông tin generic bị xóa khi runtime:
val list = listOf(1, 2, 3)
// ❌ Không thể kiểm tra generic type// if (list is List<Int>) { } // Lỗi compile
// ✅ Chỉ kiểm tra được Listif (list is List<*>) { println("It's a list")}Reified type với inline functions
Phần tiêu đề “Reified type với inline functions”inline fun <reified T> checkType(value: Any): Boolean { return value is T}
println(checkType<String>("Hello")) // trueprintln(checkType<Int>("Hello")) // false🛠️ Thực hành
Phần tiêu đề “🛠️ Thực hành”Bài tập 1: Parse user input
fun main() { val ageInput = "25" val priceInput = "99.99" val invalidInput = "abc"
// TODO: Parse sang số an toàn, mặc định 0}Lời giải:
fun main() { val ageInput = "25" val priceInput = "99.99" val invalidInput = "abc"
val age = ageInput.toIntOrNull() ?: 0 val price = priceInput.toDoubleOrNull() ?: 0.0 val invalid = invalidInput.toIntOrNull() ?: 0
println("Age: $age") // 25 println("Price: $price") // 99.99 println("Invalid: $invalid") // 0}Bài tập 2: Process different types
fun main() { val items = listOf(42, "Hello", 3.14, true, listOf(1, 2, 3))
// TODO: Xử lý từng item theo kiểu}Lời giải:
fun main() { val items: List<Any> = listOf(42, "Hello", 3.14, true, listOf(1, 2, 3))
for (item in items) { val description = when (item) { is Int -> "Integer: ${item * 2}" is String -> "String: ${item.uppercase()}" is Double -> "Double: ${"%.2f".format(item)}" is Boolean -> "Boolean: ${if (item) "Yes" else "No"}" is List<*> -> "List with ${item.size} items" else -> "Unknown" } println(description) }}Output:
Integer: 84String: HELLODouble: 3.14Boolean: YesList with 3 itemsBài tập 3: Safe conversion chain
fun main() { val config = mapOf( "port" to "8080", "timeout" to "30", "debug" to "true", "invalid" to "abc" )
// TODO: Parse thành các type đúng}Lời giải:
fun main() { val config = mapOf( "port" to "8080", "timeout" to "30", "debug" to "true", "invalid" to "abc" )
val port = config["port"]?.toIntOrNull() ?: 80 val timeout = config["timeout"]?.toIntOrNull() ?: 60 val debug = config["debug"]?.toBooleanStrictOrNull() ?: false val invalid = config["invalid"]?.toIntOrNull() ?: -1
println("Port: $port") // 8080 println("Timeout: $timeout") // 30 println("Debug: $debug") // true println("Invalid: $invalid") // -1}📱 Trong Android
Phần tiêu đề “📱 Trong Android”// Parse Intent extrasval userId = intent.getStringExtra("USER_ID")?.toIntOrNull() ?: -1
// Parse JSON responseval jsonObject = JSONObject(responseString)val count = jsonObject.optInt("count", 0)val name = jsonObject.optString("name", "")
// RecyclerView ViewHolderclass MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(item: Any) { when (item) { is HeaderItem -> bindHeader(item) is ContentItem -> bindContent(item) is FooterItem -> bindFooter(item) } }}⚠️ Lưu ý quan trọng
Phần tiêu đề “⚠️ Lưu ý quan trọng”✅ Checklist - Tự kiểm tra
Phần tiêu đề “✅ Checklist - Tự kiểm tra”Sau bài học này, bạn có thể:
- Chuyển đổi số với
toInt(),toLong(),toDouble(), etc. - Parse String an toàn với
toIntOrNull(),toDoubleOrNull() - Sử dụng
isđể kiểm tra kiểu - Hiểu Smart Cast sau khi kiểm tra
is - Phân biệt
as(unsafe) vàas?(safe) cast - Xử lý type erasure với generics
Tiếp theo: Nhập dữ liệu từ bàn phím