Kotlin menggabungkan keamanan tipe statis dengan keringkasan sintaks. Salah satu fitur kunci adalah type inference — kompilator menentukan tipe variabel dari nilai yang diberikan tanpa kita menuliskannya. Hal ini membuat kode tetap ringkas namun tetap aman karena tipe setiap variabel sudah dikenal saat kompilasi. Pada chapter ini kita akan melihat bagaimana inferensi bekerja, kapan kita perlu menambah tipe eksplisit, serta beberapa batasan yang perlu dipahami.
Cara kerja type inference #
Saat kita menulis val x = 5, kompilator memeriksa literal 5 lalu menyimpulkan tipe Int. Saat menulis val s = "halo", kompilator menyimpulkan tipe String. Inferensi terjadi pada saat kompilasi — hasilnya tetap aman secara tipe, hanya saja kita tidak perlu menuliskan tipe secara eksplisit.
Tabel berikut merangkum tipe yang disimpulkan dari literal umum:
| Literal | Tipe disimpulkan |
|---|---|
5 | Int |
5L | Long |
5.0 | Double |
5.0f | Float |
'A' | Char |
"halo" | String |
true | Boolean |
listOf(1, 2, 3) | List<Int> |
"Budi" to 25 | Pair<String, Int> |
Demonstrasi type inference #
Berikut program yang memperlihatkan tipe yang disimpulkan kompilator untuk berbagai literal:
fun main() {
val umur = 25
val berat = 65.5
val nama = "Budi"
val aktif = true
val huruf = 'K'
val daftar = listOf(1, 2, 3)
val pasangan = "Budi" to "Siti"
println("umur = $umur (${umur.javaClass.simpleName})")
println("berat = $berat (${berat.javaClass.simpleName})")
println("nama = $nama (${nama.javaClass.simpleName})")
println("aktif = $aktif (${aktif.javaClass.simpleName})")
println("huruf = $huruf (${huruf.javaClass.simpleName})")
println("daftar = $daftar (${daftar.javaClass.simpleName})")
println("pasangan= $pasangan (${pasangan.javaClass.simpleName})")
val kosong = emptyList<Int>()
println("kosong = $kosong (${kosong.javaClass.simpleName})")
val total: Long = 1_000_000L
println("total = $total (${total.javaClass.simpleName})")
}Output yang Dihasilkan:
umur = 25 (int)
berat = 65.5 (double)
nama = Budi (String)
aktif = true (boolean)
huruf = K (char)
daftar = [1, 2, 3] (ArrayList)
pasangan= (Budi, Siti) (Pair)
kosong = [] (EmptyList)
total = 1000000 (long)Mari kita amati baris-baris penting pada kode di atas:
- Baris 2 (
val umur = 25) — literal25adalah bilangan bulat dalam rentangInt, sehingga kompilator menyimpulkanInt. UntukLongkita perlu suffixL(lihat baris 16). - Baris 3 (
val berat = 65.5) — literal65.5adalah bilangan desimal, disimpulkan sebagaiDouble. UntukFloatgunakan suffixf. - Baris 6 (
val daftar = listOf(1, 2, 3)) —listOfadalah function generik; kompilator menyimpulkan tipe parameterIntdari elemen list. - Baris 7 (
val pasangan = "Budi" to "Siti") —toadalah infix function yang mengembalikanPair<String, String>. - Baris 11 (
val kosong = emptyList<Int>()) —emptyListtidak punya elemen untuk disimpulkan, sehingga tipe parameter wajib diberi eksplisit (<Int>). - Baris 14 (
val total: Long = 1_000_000L) —1_000_000Ladalah literalLong; tipe eksplisit: Longbersifat opsional di sini, tetapi berguna untuk dokumentasi.
Kapan menambah tipe eksplisit #
Meskipun inferensi sangat membantu, terdapat situasi di mana tipe eksplisit diperlukan atau dianjurkan:
- Inferensi tidak dapat menentukan tipe: misalnya
emptyList<Int>()tanpa argumen elemen. - Kita ingin tipe yang lebih luas:
val umur: Number = 25alih-alihInt. - Klarifikasi niat: tipe eksplisit membantu pembaca memahami batasan yang kita inginkan.
- API publik pada library: tipe eksplisit pada signature function publik membuat kontrak lebih jelas dan stabil.
val daftarKosong = emptyList<String>() // wajib eksplisit
val id: Long = 42 // eksplisit memaksa Long, bukan Int
val harga: Number = 99.99 // eksplisit memakai superclass Number
fun hitung(a: Int, b: Int): Int = a + b // signature publik wajib eksplisitBatasan type inference #
Inferensi Kotlin hanya bekerja pada level lokal. Beberapa batasan:
- Tidak menyimpulkan tipe dari penggunaan: kompilator hanya melihat sisi kanan
=, bukan cara variabel dipakai nanti. - Tidak otomatis widening:
val x: Long = 5sah karena konversi eksplisit dilakukan otomatis untuk literal numerik; tetapival y: Long = someIntgagal kompiler tanpa.toLong(). - Lambda parameter: parameter lambda kadang perlu tipe eksplisit jika konteks tidak cukup membantu.
Referensi Lanjutan #
- Basic types — pengantar tipe dasar Kotlin yang memperkenalkan type inference bawaan kompilator
Inferensi tipe membuat kode Kotlin ringkas tanpa mengurangi keamanan. Selanjutnya, kita akan melihat bagaimana tipe-tipe ini dipetakan ke primitive types atau reference types JVM — pembahasan tuntas pada chapter Primitive Types vs Reference Types.