Skip to Content
Kotlin📘 Ngôn ngữ Kotlin📦 Biến - val và var

Biến trong Kotlin: val và var

🎯 Mục tiêu: Hiểu sự khác biệt giữa valvar, và tại sao Kotlin khuyến khích immutability (tính bất biến).


💡 Khái niệm

Hãy tưởng tượng bạn có hai loại hộp:

Loại hộpKeywordĐặc điểm
🔒 Hộp khóavalSau khi bỏ đồ vào, không thể thay đổi
📦 Hộp mởvarCó thể thay đồ bất cứ lúc nào

Kotlin mặc định muốn bạn dùng “hộp khóa” (val) vì an toàn hơn!

val name = "Bumbii" // 🔒 Không thể thay đổi var score = 100 // 📦 Có thể thay đổi // name = "Other" // ❌ Lỗi compile! score = 150 // ✅ OK

📝 Cú pháp khai báo biến

val - Biến không thay đổi (Immutable reference)

val pi = 3.14159 val appName = "Bumbii Academy" val isActive = true // Không thể gán lại giá trị // pi = 3.14 // ❌ Compile error: Val cannot be reassigned

var - Biến có thể thay đổi (Mutable reference)

var count = 0 count = 1 // ✅ OK count = 2 // ✅ OK var userName = "Alice" userName = "Bob" // ✅ OK

🔍 Type Inference - Kotlin tự suy luận kiểu

Kotlin thông minh! Bạn không cần khai báo kiểu dữ liệu, Kotlin sẽ tự suy luận:

// Kotlin tự hiểu kiểu dữ liệu val name = "Kotlin" // String val age = 25 // Int val height = 1.75 // Double val isStudent = true // Boolean // Hoặc khai báo tường minh (explicit) val name: String = "Kotlin" val age: Int = 25 val height: Double = 1.75 val isStudent: Boolean = true

[!TIP] Best Practice: Để Kotlin tự suy luận kiểu khi giá trị đã rõ ràng. Chỉ khai báo tường minh khi cần thiết hoặc để code dễ đọc hơn.


⚠️ val không có nghĩa là object immutable!

Đây là điểm hay bị hiểu nhầm:

val numbers = mutableListOf(1, 2, 3) // Không thể gán list mới // numbers = mutableListOf(4, 5, 6) // ❌ Compile error // NHƯNG có thể thay đổi NỘI DUNG của list numbers.add(4) // ✅ OK - giờ là [1, 2, 3, 4] numbers[0] = 100 // ✅ OK - giờ là [100, 2, 3, 4]

[!WARNING] val chỉ đảm bảo reference không thay đổi, không phải nội dung bên trong object.

Nếu muốn list thực sự immutable:

val numbers = listOf(1, 2, 3) // Immutable list // numbers.add(4) // ❌ Không có method add()

🔧 Late Initialization với lateinit

Đôi khi bạn không thể khởi tạo biến ngay lập tức:

class UserProfile { // Sẽ được khởi tạo sau (ví dụ: sau khi load từ database) lateinit var userName: String fun initializeUser() { userName = "Bumbii" } fun printUser() { // Kiểm tra đã khởi tạo chưa if (::userName.isInitialized) { println("User: $userName") } else { println("User chưa được khởi tạo") } } }

[!CAUTION] lateinit chỉ dùng với:

  • var (không dùng với val)
  • Non-primitive types (không dùng với Int, Double, Boolean…)
  • Thuộc tính trong class (không dùng ở top-level hoặc local)

📌 Hằng số với const val

Để khai báo hằng số compile-time:

// Top-level hoặc trong object const val PI = 3.14159 const val MAX_USERS = 1000 const val APP_NAME = "Bumbii Academy" object Config { const val API_URL = "https://api.bumbii.com" const val TIMEOUT = 30 }
KeywordKhi nào dùng
valGiá trị không đổi trong runtime
const valGiá trị biết trước lúc compile (primitives + String)
val currentTime = System.currentTimeMillis() // ✅ Runtime value // const val currentTime = System.currentTimeMillis() // ❌ Lỗi!

📏 Quy tắc đặt tên biến

Kotlin sử dụng camelCase:

// ✅ Đúng val firstName = "John" val totalAmount = 1000 val isUserLoggedIn = true // ✅ Hằng số dùng SCREAMING_SNAKE_CASE const val MAX_RETRY_COUNT = 3 const val DATABASE_NAME = "bumbii_db" // ❌ Sai val first_name = "John" // underscore không đúng quy ước val TOTAL = 1000 // ALL CAPS cho biến thường

Quy tắc cơ bản:

  1. Bắt đầu bằng chữ cái hoặc _
  2. Không bắt đầu bằng số
  3. Không dùng keyword của Kotlin (val, var, class, fun…)
  4. Phân biệt hoa/thường (nameName)

🛠️ Thực hành

Bài tập 1: Phân biệt val và var

fun main() { // TODO: Khai báo biến cho thông tin sinh viên // - Mã sinh viên (không đổi) // - Tên sinh viên (không đổi) // - Điểm trung bình (có thể thay đổi) // - Số tín chỉ đã học (có thể tăng) }

Lời giải:

fun main() { val studentId = "SV001" // 🔒 Mã SV không đổi val studentName = "Nguyễn Văn A" // 🔒 Tên không đổi var gpa = 3.5 // 📦 Điểm có thể cập nhật var totalCredits = 30 // 📦 Tín chỉ tăng dần println("=== THÔNG TIN SINH VIÊN ===") println("Mã SV: $studentId") println("Họ tên: $studentName") println("GPA: $gpa") println("Tín chỉ: $totalCredits") // Cập nhật sau kỳ học mới gpa = 3.7 totalCredits = 45 println("\n=== SAU KỲ HỌC MỚI ===") println("GPA: $gpa") println("Tín chỉ: $totalCredits") }

Bài tập 2: Sửa lỗi trong code sau

fun main() { val userName = "Alice" userName = "Bob" // ??? const val MAX = 100 // ??? lateinit val message: String // ??? lateinit var count: Int // ??? }

Lời giải:

// Top-level hoặc trong object const val MAX = 100 fun main() { var userName = "Alice" // Đổi val → var nếu cần thay đổi userName = "Bob" // ✅ OK lateinit var message: String // lateinit chỉ dùng với var message = "Hello" var count: Int = 0 // lateinit không dùng với primitive }

📱 Trong Android / Jetpack Compose

class MainActivity : AppCompatActivity() { // lateinit thường dùng cho Views private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) } }

Jetpack Compose:

@Composable fun Counter() { // Sử dụng remember và mutableStateOf var count by remember { mutableStateOf(0) } Column { Text("Count: $count") Button(onClick = { count++ }) { Text("Tăng") } } }

✅ Checklist - Tự kiểm tra

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

  • Hiểu sự khác biệt giữa val (immutable reference) và var (mutable reference)
  • Biết khi nào nên dùng val (mặc định) và khi nào cần var
  • Hiểu rằng val không đảm bảo object immutable
  • Sử dụng lateinit var cho khởi tạo muộn
  • Phân biệt valconst val
  • Đặt tên biến đúng quy ước camelCase

Tiếp theo: Giá trị và Kiểu dữ liệu

Last updated on