Operator is dan !is memeriksa tipe sebuah nilai saat runtime, sekaligus memberikan jaminan statis kepada kompilator. Setelah pemeriksaan is berhasil, kompilator Kotlin secara otomatis memperlakukan nilai sebagai tipe yang diperiksa tanpa memerlukan cast eksplisit. Mekanisme ini disebut smart cast. Pada chapter ini kita akan membandingkan pemeriksaan tipe manual dengan smart cast, mengulas kasus di mana smart cast bekerja dan tidak bekerja, serta mengintegrasikan is dengan konstruksi when untuk pencocokan tipe.
Dasar Penggunaan is dan !is #
Operator is mengembalikan true jika nilai adalah instance dari tipe yang diperiksa (atau subtype-nya). Operator !is adalah negasinya, mengembalikan true jika nilai bukan instance tipe tersebut. Berikut ringkasan perilaku:
| Ekspresi | Hasil | Catatan |
|---|---|---|
"halo" is String | true | String literal memang String |
"halo" is CharSequence | true | String adalah subtype CharSequence |
42 is String | false | Int bukan String |
42 !is String | true | Negasi is |
42 is Number | true | Int adalah subtype Number |
null is String | false | Pemeriksaan aman terhadap null |
Operator is tidak pernah melempar galat. Pemeriksaan null is String menghasilkan false daripada NullPointerException, karena kompilator menyuntikkan pemeriksaan null internal.
Smart Cast Setelah Pemeriksaan is #
Setelah pemeriksaan is berhasil pada blok kondisional, kompilator Kotlin memperlakukan variabel sebagai tipe yang diperiksa tanpa perlu as. Inilah fitur smart cast yang membedakan Kotlin dari Java. Berikut perbandingan:
// Tanpa smart cast (perlu cast eksplisit)
val data: Any = "halo"
if (data is String) {
val panjang = (data as String).length
}
// Dengan smart cast (cast otomatis)
if (data is String) {
val panjang = data.length
}Kedua blok di atas menghasilkan perilaku yang sama, tetapi blok kedua jauh lebih ringkas karena kompilator Kotlin menyimpulkan bahwa setelah data is String mengembalikan true, variabel data dapat diakses sebagai String.
fun main() {
val data: Any = "Halo, Kotlin"
if (data is String) {
println("Panjang teks: ${data.length}")
println("Huruf besar: ${data.uppercase()}")
}
if (data !is Int) {
println("data bukan Int")
}
val input: Any = 42
if (input is Int) {
println("input + 8 = ${input + 8}")
}
// Smart cast manual dengan when
val nilai: Any = 3.14
val deskripsi = when (nilai) {
is Int -> "bilangan bulat ${nilai.toInt()}"
is Double -> "bilangan desimal $nilai"
is String -> "teks $nilai"
else -> "tipe lain"
}
println("Deskripsi: $deskripsi")
// Tanpa smart cast (perlu cast manual)
val objek: Any = "Budi"
val panjang = (objek as String).length
println("Panjang objek: $panjang")
// Smart cast dengan nullable
val nama: String? = "Siti"
if (nama != null) {
println("Nama: ${nama.uppercase()}")
}
}Output yang Dihasilkan:
Panjang teks: 12
Huruf besar: HALO, KOTLIN
data bukan Int
input + 8 = 50
Deskripsi: bilangan desimal 3.14
Panjang objek: 4
Nama: SITIMari kita uraikan baris-baris penting pada contoh di atas:
if (data is String) { ... data.length ... }memanfaatkan smart cast. Di dalam blok, kompilator memperlakukandatasebagaiString, sehinggadata.lengthdandata.uppercase()tersedia tanpaas String.if (data !is Int)adalah negasi dariis. Blok ini hanya dieksekusi jikadatabukanInt. Negasi tidak memicu smart cast, karena tipe yang diketahui hanya apa yang bukan, bukan apa yang adalah.when (nilai) { is Int -> ...; is Double -> ... }memanfaatkan smart cast per-branch. Di setiap cabang,nilaidiperlakukan sebagai tipe yang cocok. Inilah pola idiomatis Kotlin untuk type narrowing multi-cabang.(objek as String).lengthmelakukan cast eksplisit tanpa smart cast. Pendekatan ini rentanClassCastExceptionjikaobjekternyata bukanString. Hindari bila smart cast memungkinkan.if (nama != null) { nama.uppercase() }memanfaatkan smart cast untuk nullability. Setelah pemeriksaannama != nullberhasil,namadiperlakukan sebagaiStringnon-null di dalam blok. Ini adalah bentuk smart cast paling sering dipakai sehari-hari.
Kapan Smart Cast Tidak Bekerja #
Smart cast bergantung pada jaminan bahwa variabel tidak berubah tipe antara pemeriksaan dan pemakaian. Karena itu, smart cast tidak bekerja pada beberapa kasus berikut:
| Kasus | Alasan |
|---|---|
Property var di class | Thread lain dapat mengubah nilai di antara pemeriksaan dan pemakaian |
| Property yang di-override | Tidak ada jaminan subclass tidak mengubah perilaku getter |
| Variabel lokal yang ditangkap lambda | Lambda dapat memodifikasi variabel dari luar scope |
Variabel open val yang kompleks | Getter mungkin mengembalikan instance berbeda setiap pemanggilan |
Untuk kasus di atas, lakukan cast eksplisit dengan as (unsafe) atau as? (safe). Kita akan membahas kedua operator tersebut pada chapter berikutnya.
Integrasi dengan when #
Konstruksi when adalah cara paling ringkas untuk menangani banyak tipe sekaligus. Setiap cabang dapat memuat pemeriksaan is, dan smart cast aktif di dalam cabang tersebut. Pemeriksaan dilakukan berurutan dari atas ke bawah, sehingga tipe yang lebih spesifik harus ditempatkan sebelum tipe yang lebih umum. Misalnya, is Int harus muncul sebelum is Number agar tidak pernah terlewat.
Referensi Lanjutan #
- Type casts
— panduan resmi operator
isdan!isuntuk runtime type check - Smart casts
— smart cast yang dipicu oleh
ispada konteks tertentu
Dengan memahami is, !is, dan smart cast, kita siap mempelajari operator cast as dan as? yang memberi kontrol lebih langsung atas konversi tipe pada chapter berikutnya.