Operator pembanding menghasilkan nilai Boolean yang menjadi dasar percabangan program. Kotlin membedakan dua jenis kesetaraan: kesetaraan struktural (==) yang membandingkan isi, dan kesetaraan referensial (===) yang membandingkan identitas memori. Pada chapter ini kita akan membahas keenam operator pembanding, perilaku == yang dipetakan ke equals(), lalu perbedaan kedua jenis kesetaraan yang sering membingungkan pemula dari Java.

Daftar Operator Pembanding #

Kotlin mendukung operator relasi yang sama dengan bahasa turunan C:

OperatorArtiFunctionHasil untuk a=10, b=3, c=10
==sama dengan (struktural)equals()a == c → true
!=tidak sama denganequals()a != b → true
<lebih kecilcompareTo() < 0a < b → false
>lebih besarcompareTo() > 0a > b → true
<=lebih kecil atau samacompareTo() <= 0a <= c → true
>=lebih besar atau samacompareTo() >= 0a >= c → true

Untuk tipe primitif seperti Int, kompilator menerjemahkan a == b menjadi pembandingan nilai langsung. Untuk tipe reference, kompilator mengeluarkan pemanggilan equals(), dengan pemeriksaan null otomatis, sehingga ekspresi a == b aman bahkan jika a atau b bernilai null.

Kesetaraan Struktural vs Referensial #

Kesetaraan struktural (==) membandingkan isi dua objek melalui method equals(). Kesetaraan referensial (===) membandingkan apakah dua variabel menunjuk ke instance yang sama di memori. Operator !== adalah negasi dari ===.

kotlin
fun main() {
    val a = 10
    val b = 3
    val c = 10

    println("a == b: ${a == b}")
    println("a != b: ${a != b}")
    println("a == c: ${a == c}")
    println("a < b: ${a < b}")
    println("a > b: ${a > b}")
    println("a <= c: ${a <= c}")
    println("a >= c: ${a >= c}")

    val daftar1 = listOf(1, 2, 3)
    val daftar2 = listOf(1, 2, 3)
    val daftar3 = daftar1

    println("daftar1 == daftar2: ${daftar1 == daftar2}")
    println("daftar1 === daftar2: ${daftar1 === daftar2}")
    println("daftar1 === daftar3: ${daftar1 === daftar3}")
    println("daftar1 !== daftar2: ${daftar1 !== daftar2}")

    val teks1 = StringBuilder("halo")
    val teks2 = StringBuilder("halo")
    println("StringBuilder ===: ${teks1 === teks2}")
    println("StringBuilder ==: ${teks1 == teks2}")

    val banding = a.compareTo(b)
    println("a.compareTo(b) = $banding")
}

Output yang Dihasilkan:

text
a == b: false
a != b: true
a == c: true
a < b: false
a > b: true
a <= c: true
a >= c: true
daftar1 == daftar2: true
daftar1 === daftar2: false
daftar1 === daftar3: true
daftar1 !== daftar2: true
StringBuilder ===: false
StringBuilder ==: false
a.compareTo(b) = 1

Mari kita uraikan bagian penting pada contoh di atas:

  1. a == c menghasilkan true karena nilai Int 10 dibandingkan secara langsung. Kompilator menggunakan instruksi bytecode primitif tanpa pemanggilan function.
  2. daftar1 == daftar2 menghasilkan true. List di Kotlin mengimplementasikan equals() dengan membandingkan elemen satu per satu, sehingga dua list dengan isi yang sama dianggap setara.
  3. daftar1 === daftar2 menghasilkan false. Meskipun isinya sama, kedua variabel menunjuk ke objek List yang berbeda di memori heap.
  4. daftar1 === daftar3 menghasilkan true karena daftar3 = daftar1 membuat kedua variabel menunjuk ke instance yang sama.
  5. StringBuilder == menghasilkan false. Berbeda dengan List, StringBuilder tidak meng-override equals(), sehingga == jatuh ke implementasi default Object.equals() yang membandingkan referensi memori.
  6. a.compareTo(b) mengembalikan bilangan bulat: negatif jika a < b, nol jika sama, positif jika a > b. Operator <, >, <=, >= dipetakan ke function compareTo() ini.

Perilaku compareTo dan Comparable #

Operator <, >, <=, dan >= dipanggil melalui function compareTo() yang mengembalikan Int. Aturan yang harus dipatuhi: tanda hasil konsisten dengan operator pembanding. Jika a.compareTo(b) < 0, maka a < b harus true. Class yang mengimplementasikan Comparable<T> otomatis mendukung keempat operator relasi tanpa perlu menulis operator fun tambahan.

String Comparison #

String di Kotlin dibandingkan secara struktural melalui equals(), sehingga "halo" == "halo" selalu true. Jika ingin membandingkan identitas memori (misalnya untuk verifikasi string pooling), gunakan ===. Untuk perbandingan leksikografis yang lebih canggih (case-insensitive, locale-aware), gunakan String.compareTo(other, ignoreCase) atau API Collator dari Java.

kotlin Contoh: perbandingan string dengan ignoreCase
val nama1 = "Budi"
val nama2 = "budi"
println(nama1.equals(nama2, ignoreCase = true)) // true

Referensi Lanjutan #

Dengan pemahaman tentang ==, ===, dan operator relasi, kita dapat membangun kondisi percabangan. Selanjutnya kita akan menggabungkan beberapa kondisi menggunakan operator logika &&, ||, dan ! pada chapter berikutnya.