Skip to Content
Kotlin📘 Ngôn ngữ Kotlin🔄 Chuyển đổi Kiểu dữ liệu

Chuyển đổi kiểu dữ liệu (Type Conversion) trong Kotlin

🎯 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

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()

📝 Conversion Methods cho số

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

// 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()

🔢 Chuyển đổi String ↔ Số

String → Số

// 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()

Cách không an toàn (throw exception)

val number = "42".toInt() // 42 val error = "abc".toInt() // ❌ NumberFormatException!

[!TIP] Luôn dùng toIntOrNull() khi parse input từ người dùng!

Số → String

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"

🎯 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

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

fun processNotNull(value: Any?) { if (value !is String) { return // Exit early } // value is String from here println(value.uppercase()) }

⚠️ 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?

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

Kiểm tra kiểu với is

val value: Any = "Kotlin" println(value is String) // true println(value is Int) // false println(value !is Int) // true

Kiểm tra nullable với is

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

📊 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 List if (list is List<*>) { println("It's a list") }

Reified type với inline functions

inline fun <reified T> checkType(value: Any): Boolean { return value is T } println(checkType<String>("Hello")) // true println(checkType<Int>("Hello")) // false

🛠️ 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: 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 }

📱 Trong Android

// 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) } } }

⚠️ Lưu ý quan trọng

[!WARNING] Cẩn thận với Float precision:

val f = 3.14f val d = f.toDouble() println(d) // 3.140000104904175 (không chính xác!) // Workaround val accurate = f.toString().toDouble() // 3.14

[!CAUTION] Overflow khi converting:

val big = 1000L val small = big.toByte() println(small) // -24 (overflow, không phải 1000!)

✅ 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

Last updated on