Variabel adalah wadah bernama yang menyimpan nilai selama program berjalan. Kotlin membagi variabel menjadi dua jenis: val untuk variabel read-only dan var untuk variabel yang dapat diubah. Pemilihan antara keduanya menentukan apakah kode kita mudah dipahami dan minim galat, atau justru rentan terhadap kesalahan. Pada chapter ini kita akan membedah perbedaan val dan var, kapan memilih salah satunya, serta jebakan umum terkait imutabilitas compile-time versus runtime.
Apa itu val dan var #
Keyword val mendeklarasikan variabel yang referensinya tidak dapat diubah setelah diinisialisasi. Keyword var mendeklarasikan variabel yang referensinya dapat diubah kapan saja. Kedua keyword ini bersifat eksklusif — sebuah variabel hanya boleh satu di antaranya.
val nama: String = "Budi" // read-only, tidak bisa ditulis ulang
var skor: Int = 10 // mutable, bisa ditulis ulang
skor = 15 // sah
// nama = "Siti" // galat kompilasi: val cannot be reassignedPerbedaan utama antara val dan var dirangkum pada tabel berikut:
| Aspek | val | var |
|---|---|---|
| Reassign referensi | Tidak boleh | Boleh |
| Mutasi isi objek | Bisa (jika objek mutable) | Bisa |
| Default direkomendasikan | Ya | Hanya bila perlu |
| Thread-safe lebih mudah | Ya | Tidak otomatis |
Mengapa val lebih disarankan #
Variabel val membuat kode lebih mudah diprediksi karena nilai pengikatannya tidak berubah setelah inisialisasi. Pembaca kode tidak perlu mengikuti seluruh jalur eksekusi untuk memastikan nilai akhir sebuah val. Saat kita menggunakan val, kompilator memverifikasi bahwa variabel hanya ditulis sekali, sehingga banyak kelas galat logika tidak akan lolos ke tahap runtime.
Berikut contoh nyata penggunaan val dan var dalam satu program:
fun main() {
val nama: String = "Budi"
println("Nama: $nama")
var skor: Int = 10
println("Skor awal: $skor")
skor = 15
println("Skor setelah ditambah: $skor")
val daftarAnggota = mutableListOf("Budi", "Siti")
daftarAnggota.add("Dewi")
println("Daftar anggota: $daftarAnggota")
val config = buildMap {
put("host", "localhost")
put("port", 8080)
}
println("Config: $config")
println("Tipe config: ${config.javaClass.simpleName}")
println("Tipe daftarAnggota: ${daftarAnggota.javaClass.simpleName}")
}Output yang Dihasilkan:
Nama: Budi
Skor awal: 10
Skor setelah ditambah: 15
Daftar anggota: [Budi, Siti, Dewi]
Config: {host=localhost, port=8080}
Tipe config: MapBuilder
Tipe daftarAnggota: ArrayListMari kita amati baris-baris kode di atas:
- Baris 2 (
val nama: String = "Budi") — variabelnamabersifat read-only; referensi tidak dapat diganti, tetapi karenaStringsendiri immutable, keseluruhan nilai tidak berubah. - Baris 6 (
var skor: Int = 10) —varmemungkinkan penulisan ulang. Baris 8 (skor = 15) sah karenavarmengizinkan reassign. - Baris 10 (
val daftarAnggota = mutableListOf(...)) —valhanya melindungi referensidaftarAnggota, bukan isi list. Kita tetap dapat memanggildaftarAnggota.add(...)karena isi list bersifat mutable. - Baris 14 (
val config = buildMap { ... }) —buildMapmenghasilkanMapimmutable (read-only). Kombinasival+ koleksi immutable memberikan jaminan ganda bahwa nilai tidak akan berubah.
Compile-time vs runtime immutability #
Pada val, jaminan read-only berlaku pada level referensi. Apabila val merujuk ke objek mutable (seperti MutableList), isi objek tetap dapat berubah melalui method yang dimiliki objek tersebut. Inilah perbedaan antara imutabilitas binding (compile-time) dan imutabilitas objek (runtime).
val angka = mutableListOf(1, 2, 3)
angka.add(4) // sah: isi list berubah, tetapi referensi tetap
// angka = mutableListOf() // galat: val tidak boleh ditulis ulang
println(angka) // [1, 2, 3, 4]Untuk benar-benar membuat data tidak berubah, gunakan tipe koleksi immutable seperti listOf, setOf, atau mapOf. Kombinasi val + koleksi immutable memberi jaminan kuat bahwa data tidak akan dimodifikasi dari referensi tersebut.
Referensi Lanjutan #
- Basic types
— pengantar tipe dasar Kotlin yang menjelaskan deklarasi
valdanvarsebagai pondasi variabel - Properties
— dokumentasi properti Kotlin yang merincikan perilaku
val(read-only) vsvar(mutable)
Dengan memahami batas antara val dan var, kita siap melihat bagaimana cara mendeklarasikan dan menginisialisasi variabel dengan tepat — termasuk pola lateinit dan lazy yang akan kita bahas pada chapter Deklarasi dan Inisialisasi.