Setelah memahami perbedaan kategori tipe nullable dan non-nullable, kita perlu tahu cara mendeklarasikan variabel nullable dan mengelola nilainya sepanjang eksekusi program. Variabel nullable dapat dibuat dengan val (read-only) maupun var (mutable), dan setiap perubahan nilainya tetap diawasi oleh kompilator. Pada chapter ini kita akan menulis berbagai bentuk deklarasi variabel nullable, mengamati perilakunya saat diisi dengan nilai maupun null, serta melihat bagaimana kompilator menolak penetapan null pada tipe non-nullable.
Deklarasi Variabel Nullable #
Cara paling langsung mendeklarasikan variabel nullable adalah dengan menambahkan ? pada tipe yang disebutkan. Sintaks ini berlaku untuk semua tipe referensi seperti String, Int, Long, maupun tipe buatan sendiri.
fun main() {
val nama: String = "Budi"
println("Nama non-nullable: $nama")
var namaOpsional: String? = null
println("NamaOpsional mula-mula: $namaOpsional")
namaOpsional = "Siti"
println("NamaOpsional setelah diisi: $namaOpsional")
namaOpsional = null
println("NamaOpsional setelah di-null-kan: $namaOpsional")
val umur: Int? = null
println("Umur nullable: $umur")
val harga: Double? = 12_500.0
println("Harga nullable: $harga, pakai safe call: ${harga?.toInt()}")
val data: List<String?> = listOf("A", null, "B")
println("List berisi null: $data")
val idPengguna: Long? = null
val id: Long = idPengguna ?: 0L
println("ID default dari nullable: $id")
val panjang: Int? = namaOpsional?.length
println("Panjang dari namaOpsional: $panjang")
var status: String? = "aktif"
val panjangStatus = status?.length
println("Status=$status, panjang=$panjangStatus")
status = null
val panjangStatusSekarang = status?.length
println("Status=$status, panjang=$panjangStatusSekarang")
val angkaHeksadesimal: Int? = 0xFF
println("Angka hex nullable: $angkaHeksadesimal")
val elemenPertama: String? = data.first()
println("Elemen pertama dari data: $elemenPertama")
}Output yang Dihasilkan:
Nama non-nullable: Budi
NamaOpsional mula-mula: null
NamaOpsional setelah diisi: Siti
NamaOpsional setelah di-null-kan: null
Umur nullable: null
Harga nullable: 12500.0, pakai safe call: 12500
List berisi null: [A, null, B]
ID default dari nullable: 0
Panjang dari namaOpsional: null
Status=aktif, panjang=5
Status=null, panjang=null
Angka hex nullable: 255
Elemen pertama dari data: AMari kita uraikan baris-baris penting pada contoh di atas:
- Baris 2 (
val nama: String = "Budi"): variabel non-nullable denganval. Variabel ini tidak dapat diubah nilainya maupun dijadikannull. - Baris 5 (
var namaOpsional: String? = null): variabel mutable nullable. Kata kuncivarmemungkinkan penetapan ulang, termasuk kembali kenullseperti terlihat pada baris 8. - Baris 10 (
val umur: Int? = null): variabel read-only nullable.valmencegah penetapan ulang, namun tetap mengizinkan nilai awal berupanull. - Baris 13 (
harga?.toInt()): variabel nullable yang berisi nilai tetap perlu safe call?.untuk mengakses method-nya. Hasilnya juga bertipe nullable (Int?). - Baris 16 (
List<String?>): tipe elemen list juga dapat nullable. Hal ini umum saat membaca data dari sumber eksternal yang mungkin mengandung elemen kosong. - Baris 19 (
idPengguna ?: 0L): operator Elvis memberi nilai default0LbilaidPenggunanull. Hasilnya bertipe non-nullableLongsehingga aman dipakai pada operasi aritmetika. - Baris 22 (
namaOpsional?.length): setiap kali kita menetapkan ulang nilainamaOpsional(misalnya kenulldi baris 8), kompilator tetap mengetahui tipenya tetapString?sehingga akses method tetap wajib memakai?.atau pengecekan eksplisit. - Baris 32 (
val elemenPertama: String? = data.first()): functionfirst()padaList<String?>mengembalikanString?karena elemen pertama list bisa jadi adalahnull. Tipe kembalian mengikuti tipe elemen.
Galat Compile-time pada Penetapan Null #
Kompilator Kotlin akan menolak kode yang mencoba menetapkan null ke tipe non-nullable. Perhatikan contoh berikut yang sengaja dibuat salah:
val nama: String = nullSaat dikompilasi, kotlinc akan mengeluarkan pesan galat seperti berikut:
error: null can not be a value of a non-null type String
val nama: String = null
^Pesan tersebut menjelaskan secara eksplisit bahwa tipe String tidak menerima nilai null. Untuk membuat variabel yang dapat menyimpan null, kita harus menggunakan tipe nullable String?.
Pertimbangan Memilih val atau var untuk Variabel Nullable #
Pilihan antara val dan var pada variabel nullable memengaruhi cara kode dirawat. Variabel val dengan tipe nullable cocok untuk nilai yang hanya dibaca sekali namun mungkin tidak tersedia saat deklarasi — misalnya hasil pencarian database yang bisa jadi tidak ditemukan. Variabel var dengan tipe nullable cocok untuk state yang berubah sepanjang siklus hidup objek, namun setiap akses tetap perlu penanganan eksplisit karena nilai bisa jadi null di tengah jalan.
Salah satu kesalahan umum adalah memakai var x: T? = null sebagai pengganti inisialisasi tertunda. Pola ini memaksa setiap akses berikutnya memakai ?. atau pengecekan != null, padahal kita tahu nilai akan diisi sebelum pertama kali dipakai. Pendekatan yang lebih aman adalah memakai lateinit var (untuk tipe non-nullable seperti String dan Int) atau by lazy (untuk inisialisasi sekali pakai). Topik ini akan dibahas tuntas pada chapter Null Safety Best Practices.
Referensi Lanjutan #
- Null-safety
— panduan resmi mendeklarasikan variabel nullable dan menugaskan
null
Dengan kemampuan mendeklarasikan variabel nullable, langkah berikutnya adalah memanggil method pada variabel tersebut dengan aman. Materi tentang safe call operator ?. akan kita bahas pada chapter berikutnya.