Pada chapter data class kita melihat bahwa kompilator Kotlin otomatis menghasilkan lima method utama: equals, hashCode, toString, copy, dan componentN. Dua method terakhir sering luput diperhatikan namun sangat berguna — copy memungkinkan pembuatan instance baru yang hampir sama dengan instance lama, dan componentN mendukung destrukturisasi yang membuat kode pengaksesan property lebih ringkas. Pada chapter ini kita akan memakai method copy dengan modifikasi sebagian property, melakukan destrukturisasi pada instance dan dalam loop, serta melihat pola umum seperti swap dua value memanfaatkan destrukturisasi.
Method copy #
Method copy dihasilkan otomatis untuk setiap property di primary constructor data class. Signature method ini menerima parameter opsional untuk setiap property — bila parameter tidak diberikan, nilai dari instance asli dipakai. Bila parameter diberikan, nilai baru menggantikan nilai asli pada instance hasil.
val u1 = Pengguna("Budi", 25, "Jakarta")
val u3 = u1.copy(umur = 26)
// u3 = Pengguna(nama=Budi, umur=26, kota=Jakarta)Method copy tidak mengubah instance asli — instance u1 tetap memiliki umur=25. Pola ini sesuai dengan konsep immutable data — instance yang sudah dibuat tidak diubah; perubahan dibuat dengan membuat instance baru. Karena copy mengembalikan instance baru, dua instance yang berbeda tetap ada di heap — operator === mengembalikan false untuk instance asli dan hasil copy.
Method componentN dan Destrukturisasi #
Kompilator Kotlin menghasilkan method component1(), component2(), dan seterusnya untuk setiap property di primary constructor data class. Method ini mengembalikan nilai property ke-N. Method componentN mendukung sintaks destrukturisasi — val (a, b, c) = instance — yang memanggil component1(), component2(), component3() untuk mengisi masing-masing variabel.
val u1 = Pengguna("Budi", 25, "Jakarta")
val (nama, umur, kota) = u1
// nama = "Budi", umur = 25, kota = "Jakarta"Destrukturisasi tidak terbatas pada data class. Pair, Triple, Map.Entry, dan class lain yang menyediakan method componentN juga dapat didestrukturisasi. Pola ini sering muncul di loop for ((key, value) in map) untuk iterasi entry map.
Contoh Lengkap #
Contoh berikut mendemonstrasikan method copy dengan modifikasi sebagian, destrukturisasi pada instance, destrukturisasi di loop list dan map, destrukturisasi parsial dengan _, dan pola swap dua poin memanfaatkan destrukturisasi.
// copy_dan_component_functions.kt
// Mendemonstrasikan `copy` dan `componentN` (destructuring) untuk data class.
data class Pengguna(val nama: String, val umur: Int, val kota: String)
data class Buku(
val judul: String,
val penulis: String,
val tahun: Int,
val harga: Int = 0,
)
data class Item(val id: Long, val nama: String, val qty: Int) {
fun total(harga: Int): Int = qty * harga
}
data class Poin(val x: Int, val y: Int)
fun main() {
val u1 = Pengguna("Budi", 25, "Jakarta")
println("Asli: $u1")
// copy tanpa argumen: salinan identik.
val u2 = u1.copy()
println("Copy tanpa modifikasi: $u2")
println("u1 === u2 ? ${u1 === u2}")
println("u1 == u2 ? ${u1 == u2}")
println()
// copy dengan modifikasi sebagian field.
val u3 = u1.copy(umur = 26)
println("Copy umur=26: $u3")
val u4 = u1.copy(nama = "Andi", kota = "Bandung")
println("Copy nama=Andi, kota=Bandung: $u4")
println("Asli tetap: $u1")
println()
// Destructuring via componentN.
val (nama, umur, kota) = u1
println("Destructure u1 -> nama=$nama, umur=$umur, kota=$kota")
println("Komponen 1 (component1): ${u1.component1()}")
println("Komponen 2 (component2): ${u1.component2()}")
println("Komponen 3 (component3): ${u1.component3()}")
println()
// Destructuring di loop.
val bukuList = listOf(
Buku("Belajar Kotlin", "Budi", 2026, 75_000),
Buku("Belajar Python", "Siti", 2024, 80_000),
Buku("Belajar Go", "Dewi", 2025, 90_000),
)
println("Daftar buku (destructuring di loop):")
for ((judul, penulis, tahun, harga) in bukuList) {
println(" - $judul oleh $penulis ($tahun) — Rp$harga")
}
println()
// Destructuring parsial dengan _.
val (judul, _, _, harga) = bukuList[0]
println("Destructure parsial -> judul=$judul, harga=$harga")
println()
// Destructuring untuk pemetaan key-value map.
val kodePos = mapOf(
"Jakarta" to 10110,
"Bandung" to 40111,
"Surabaya" to 60111,
)
println("Daftar kode pos (destructuring map entry):")
for ((kota, kode) in kodePos) {
println(" $kota: $kode")
}
println()
// Pemakaian componentN dengan function yang mengembalikan data class.
val item = Item(1L, "Buku Tulis", 3)
val (idItem, namaItem, qtyItem) = item
println("Item -> id=$idItem, nama=$namaItem, qty=$qtyItem")
println("Total harga (5000 x ${item.qty}): ${item.total(5000)}")
println()
// Swap dua poin via destructuring.
var p1 = Poin(1, 2)
var p2 = Poin(3, 4)
println("Sebelum swap: p1=$p1, p2=$p2")
p1 = p2.also { p2 = p1 }
println("Setelah swap: p1=$p1, p2=$p2")
}Output yang Dihasilkan:
Asli: Pengguna(nama=Budi, umur=25, kota=Jakarta)
Copy tanpa modifikasi: Pengguna(nama=Budi, umur=25, kota=Jakarta)
u1 === u2 ? false
u1 == u2 ? true
Copy umur=26: Pengguna(nama=Budi, umur=26, kota=Jakarta)
Copy nama=Andi, kota=Bandung: Pengguna(nama=Andi, umur=25, kota=Bandung)
Asli tetap: Pengguna(nama=Budi, umur=25, kota=Jakarta)
Destructure u1 -> nama=Budi, umur=25, kota=Jakarta
Komponen 1 (component1): Budi
Komponen 2 (component2): 25
Komponen 3 (component3): Jakarta
Daftar buku (destructuring di loop):
- Belajar Kotlin oleh Budi (2026) — Rp75000
- Belajar Python oleh Siti (2024) — Rp80000
- Belajar Go oleh Dewi (2025) — Rp90000
Destructure parsial -> judul=Belajar Kotlin, harga=75000
Daftar kode pos (destructuring map entry):
Jakarta: 10110
Bandung: 40111
Surabaya: 60111
Item -> id=1, nama=Buku Tulis, qty=3
Total harga (5000 x 3): 15000
Sebelum swap: p1=Poin(x=1, y=2), p2=Poin(x=3, y=4)
Setelah swap: p1=Poin(x=3, y=4), p2=Poin(x=1, y=2)Mari kita bedah kode di atas:
val u2 = u1.copy(): copy tanpa argumen membuat salinan identik.u1 === u2mengembalikanfalse— instance berbeda di heap, namunu1 == u2mengembalikantruekarenaequalsmembandingkan struktur property.val u3 = u1.copy(umur = 26): copy dengan satu argumen —umurdiganti26, dua property lain (nama,kota) tetap membawa nilai dariu1. HasilnyaPengguna(nama=Budi, umur=26, kota=Jakarta). Property yang tidak disebut tetap membawa nilai asli.val u4 = u1.copy(nama = "Andi", kota = "Bandung"): copy dengan dua argumen. Hanyaumuryang dipertahankan dari instance asli.val (nama, umur, kota) = u1: destrukturisasi. Sintaks ini memanggilu1.component1()untuk mengisinama,u1.component2()untuk mengisiumur, danu1.component3()untuk mengisikota. Tanpa destrukturisasi, kita harus menulis tiga barisval nama = u1.nama; val umur = u1.umur; val kota = u1.kota.u1.component1(),u1.component2(),u1.component3(): memanggil methodcomponentNsecara eksplisit. Output membuktikancomponent1()mengembalikan"Budi",component2()mengembalikan25, dancomponent3()mengembalikan"Jakarta".for ((judul, penulis, tahun, harga) in bukuList): destrukturisasi di loop. Setiap iterasi mengambil satu instanceBukudari list dan mendestrukturisasi ke empat variabel. Sintaks ini membuat body loop lebih ringkas — tidak perlu menulisbuku.judul,buku.penulis, dst.val (judul, _, _, harga) = bukuList[0]: destrukturisasi parsial memakai_untuk property yang tidak diinginkan. Kita hanya pedulijuduldanharga, jadipenulisdantahundiabaikan dengan_. Tanpa_, kompilator akan mengeluh karena jumlah variabel tidak sesuai jumlah property.for ((kota, kode) in kodePos): destrukturisasi entry map. Setiap iterasi mengambil satuMap.Entry<String, Int>. Entry menyediakancomponent1()(key) dancomponent2()(value), sehingga dapat didestrukturisasi menjadi(kota, kode). Pola ini menggantikan pemanggilan verboseentry.keydanentry.value.val (idItem, namaItem, qtyItem) = item: destrukturisasi instance data classItem. Variabel dapat diberi nama bebas — tidak harus sama dengan nama property asli.p1 = p2.also { p2 = p1 }: pola swap memanfaatkanalso. Fungsialsomenerima lambda yang menerima receiver (p2) sebagai parameterit. Lambda dieksekusi dulu (mengisip2 = p1), kemudian nilai receiver (p2asli) dikembalikan dan ditugaskan kep1. Hasil akhir: nilaip1danp2bertukar.
Pola Umum Destrukturisasi #
Destrukturisasi muncul di banyak pola umum Kotlin:
- Loop list:
for ((nama, umur) in daftarPengguna)lebih ringkas darifor (p in daftarPengguna) { val nama = p.nama; val umur = p.umur }. - Loop map:
for ((k, v) in map)menggantikanfor (entry in map.entries) { entry.key; entry.value }. - Return function: function yang mengembalikan
PairatauTripledapat didestrukturisasi di pemanggil —val (status, pesan) = validasi(input). - Property ignore: gunakan
_untuk property yang tidak diperlukan — menjaga kode tetap jelas tentang variabel yang dipakai.
Referensi Lanjutan #
- Data classes
— bagian
copy()dancomponentN()yang dihasilkandata class
Ringkasan #
Method copy menghasilkan instance baru dengan opsi mengganti sebagian property — instance asli tidak berubah. Method componentN mendukung destrukturisasi yang membuat pengaksesan property lebih ringkas, baik dalam deklarasi variabel, loop list, maupun loop map. Kedua method dihasilkan otomatis oleh data class dan merupakan alat utama untuk bekerja dengan data secara idiomatik di Kotlin. Pada chapter OOP Design Principles berikutnya, kita akan merangkum prinsip desain berorientasi object yang membimbing penggunaan fitur-fitur Kotlin secara sehat.