Operator unary bekerja pada satu operand. Kotlin menyediakan operator prefix +, -, !, ++, --, serta bentuk postfix ++ dan --. Yang membedakan prefix dan postfix adalah waktu pengembalian nilai: prefix mengembalikan nilai hasil modifikasi, sementara postfix mengembalikan nilai lama sebelum modifikasi. Pada chapter ini kita akan membahas perilaku setiap operator unary, perbedaan prefix dan postfix yang sering membingungkan, dan pola penggunaan ++ pada loop counter.

Daftar Operator Unary #

Berikut ringkasan operator unary Kotlin:

OperatorPosisiFunctionContohHasil
+prefixunaryPlus()+55
-prefixunaryMinus()-5-5
!prefixnot()!truefalse
++prefixinc()++aa+1 (kembali hasil baru)
++postfixinc()a++a lama, lalu a naik
--prefixdec()--aa-1 (kembali hasil baru)
--postfixdec()a--a lama, lalu a turun

Setiap operator unary dipetakan ke function dengan nama khusus, sehingga tipe buatan kita dapat mendefinisikan perilaku khusus. Misalnya, class BigDecimal di Java mengimplementasikan unaryMinus() sehingga -bigDecimal menghasilkan BigDecimal baru dengan tanda berlawanan.

Prefix vs Postfix #

Perbedaan utama prefix dan postfix terletak pada nilai yang dikembalikan oleh ekspresi. Prefix ++a menambah nilai a terlebih dahulu, lalu mengembalikan nilai baru sebagai hasil ekspresi. Postfix a++ mengembalikan nilai lama sebagai hasil ekspresi terlebih dahulu, baru kemudian menambah a. Keduanya pada akhirnya menaikkan a sebesar satu, tetapi waktu pengembalian berbeda.

kotlin
fun main() {
    var pengunjung = 0

    pengunjung++
    println("Pengunjung setelah ++ (post): $pengunjung")
    pengunjung++
    println("Pengunjung setelah ++ (post): $pengunjung")
    pengunjung--
    println("Pengunjung setelah -- (post): $pengunjung")

    var nomor = 5
    val naikDulu = ++nomor
    println("++nomor -> nomor=$nomor, hasil=$naikDulu")

    var nilai = 5
    val pakaiDulu = nilai++
    println("nilai++ -> nilai=$nilai, hasil=$pakaiDulu")

    val positif = 7
    val negatif = -positif
    val tetapPositif = +positif
    println("positif=$positif, negatif=$negatif, tetapPositif=$tetapPositif")

    val benar = true
    val salah = !benar
    println("benar=$benar, !benar=$salah")

    var suhu = 0
    repeat(3) { suhu++ }
    println("Suhu counter setelah repeat 3x: $suhu")

    var i = 0
    while (i < 3) {
        i++
        println("Iterasi ke-$i")
    }
}

Output yang Dihasilkan:

text
Pengunjung setelah ++ (post): 1
Pengunjung setelah ++ (post): 2
Pengunjung setelah -- (post): 1
++nomor -> nomor=6, hasil=6
nilai++ -> nilai=6, hasil=5
positif=7, negatif=-7, tetapPositif=7
benar=true, !benar=false
Suhu counter setelah repeat 3x: 3
Iterasi ke-1
Iterasi ke-2
Iterasi ke-3

Mari kita bedah perbedaan prefix dan postfix pada contoh di atas:

  1. pengunjung++ adalah postfix. Variabel pengunjung naik dari 0 ke 1, tetapi ekspresi mengembalikan nilai lama 0. Karena hasil tidak ditangkap, efeknya hanya menambah counter. Pada baris berikutnya, println mencetak nilai baru 1.
  2. ++nomor adalah prefix. Variabel nomor naik dari 5 ke 6 terlebih dahulu, lalu ekspresi mengembalikan 6. val naikDulu = ++nomor menangkap 6 sebagai hasil. Inilah perbedaan kunci: prefix menjamin naikDulu == nomor.
  3. nilai++ adalah postfix. Variabel nilai naik dari 5 ke 6, tetapi ekspresi mengembalikan nilai lama 5. val pakaiDulu = nilai++ menangkap 5. Setelah eksekusi, nilai == 6 tetapi pakaiDulu == 5.
  4. -positif memanggil unaryMinus(). Pada Int, ini membalik tanda bilangan. +positif memanggil unaryPlus(), yang pada Int tidak mengubah apa pun dan jarang dipakai.
  5. !benar memanggil not(). Pada Boolean, ini membalik nilai: true menjadi false, false menjadi true. Sering dipakai pada kondisi if (!isValid).
  6. repeat(3) { suhu++ } menjalankan lambda tiga kali. Setiap iterasi menambah suhu satu. Hasil akhir suhu = 3.
  7. while (i < 3) { i++; println(...) } adalah pola counter klasik. i dimulai dari 0, naik tiap iterasi, dan loop berhenti ketika i mencapai 3.

Negasi pada Tipe Numerik dan Boolean #

Operator unary - bekerja pada semua tipe numerik (Byte, Short, Int, Long, Float, Double). Untuk tipe bertanda minimal, hasil negasi Int.MIN_VALUE tetap Int.MIN_VALUE karena overflow. Gunakan Long jika rentang nilai mungkin melampaui batas.

Operator ! hanya bekerja pada Boolean. Tidak ada !1 seperti di C. Untuk negasi bitwise pada integer, gunakan function inv() yang membalik setiap bit.

Pola Counter yang Aman #

Hindari menempatkan ++ atau -- di dalam ekspresi kompleks. Sintaks seperti arr[i++] = arr[j++] dapat menyebabkan bug sulit dilacak karena urutan evaluasi samping tidak selalu intuitif. Pisahkan menjadi dua baris bila memungkinkan:

kotlin Contoh: pemisahan counter untuk kejelasan
val indeks = i
arr[indeks] = arr[indeks] + 1
i = indeks + 1

Referensi Lanjutan #

Dengan memahami operator unary prefix dan postfix, kita siap berlatih menggunakan rentang nilai dengan operator .., until, downTo, dan step pada chapter berikutnya.