Bỏ qua để đến nội dung

🔄 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.


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 minh
val longValue: Long = intValue.toLong()

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()
// Int → Long
val count = 1000000
val bigCount = count.toLong()
// Double → Int (mất phần thập phân)
val price = 99.99
val roundedPrice = price.toInt() // 99
// Float ↔ Double
val floatVal = 3.14f
val doubleVal = floatVal.toDouble()

// Cách an toàn (trả về null nếu không parse được)
val str = "42"
val number = str.toIntOrNull() // 42
val invalid = "abc".toIntOrNull() // null
// Các kiểu khác
val long = "1000000".toLongOrNull()
val double = "3.14".toDoubleOrNull()
val float = "3.14".toFloatOrNull()
val number = "42".toInt() // 42
val error = "abc".toInt() // ❌ NumberFormatException!
val number = 42
val str = number.toString() // "42"
// Format số
val price = 15000000
val formatted = "%,d".format(price) // "15,000,000"
val decimal = 3.14159
val fixed = "%.2f".format(decimal) // "3.14"

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}")
}
}
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"
}
fun processNotNull(value: Any?) {
if (value !is String) {
return // Exit early
}
// value is String from here
println(value.uppercase())
}

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!

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)

val value: Any = "Kotlin"
println(value is String) // true
println(value is Int) // false
println(value !is Int) // true
val nullableValue: Any? = null
println(nullableValue is String) // false
println(nullableValue is String?) // Không cần - dùng null check
println(nullableValue == null) // true

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 List
if (list is List<*>) {
println("It's a list")
}
inline fun <reified T> checkType(value: Any): Boolean {
return value is T
}
println(checkType<String>("Hello")) // true
println(checkType<Int>("Hello")) // false

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: 84
String: HELLO
Double: 3.14
Boolean: Yes
List with 3 items

Bà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
}

// Parse Intent extras
val userId = intent.getStringExtra("USER_ID")?.toIntOrNull() ?: -1
// Parse JSON response
val jsonObject = JSONObject(responseString)
val count = jsonObject.optInt("count", 0)
val name = jsonObject.optString("name", "")
// RecyclerView ViewHolder
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: Any) {
when (item) {
is HeaderItem -> bindHeader(item)
is ContentItem -> bindContent(item)
is FooterItem -> bindFooter(item)
}
}
}


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