Case class adalah kelas yang dideklarasikan dengan kata kunci case dan dirancang untuk data yang nilainya tetap setelah dibuat. Compiler menghasilkan sejumlah anggota otomatis untuknya, antara lain toString yang menampilkan seluruh field, equals dan hashCode yang membandingkan isi, metode copy untuk membuat salinan dengan sebagian perubahan, serta ekstraktor yang mendukung destructuring. Topik ini membahas kelompok anggota tersebut pada contoh inventaris alat laboratorium, beserta pertimbangan memilih case class dibandingkan dengan kelas biasa.
Anggota yang dihasilkan compiler#
Setiap parameter pada deklarasi case class otomatis menjadi field val yang dapat diakses dari luar dan tidak dapat diubah, sehingga data yang dibawa instance tetap sama sepanjang hidupnya. Objek companion-nya juga mendapat metode apply, sehingga instance dibuat tanpa kata new. Selain itu, compiler menghasilkan toString yang mencetak nama kelas beserta seluruh fieldnya, sehingga isi data dapat diperiksa tanpa menulis kode pemformatan manual.
Program berikut mendeklarasikan case class LabItem untuk catatan alat laboratorium, membuat dua instance dengan isi yang sama, lalu membandingkan dan menyalinnya.
// case class untuk data alat laboratorium
case class LabItem(name: String, code: String, quantity: Int)
@main def inventory(): Unit =
val m1 = LabItem("Mikroskop", "MIK-01", 4)
val m2 = LabItem("Mikroskop", "MIK-01", 4)
// toString otomatis menampilkan nama kelas beserta seluruh fieldnya
println(m1)
// kesetaraan struktural: isi yang dibandingkan, bukan alamat memori
println(m1 == m2)
// copy menghasilkan instance baru dengan sebagian field berubah
val m3 = m1.copy(quantity = 7)
println(m3)
println(m1 == m3)# menjalankan program lab-item.scala
scala-cli run lab-item.scalaLabItem(Mikroskop,MIK-01,4)
true
LabItem(Mikroskop,MIK-01,7)
falseBaris pertama memperlihatkan keluaran toString yang mencantumkan ketiga field tanpa kode tambahan apa pun. Baris kedua dan keempat adalah hasil perbandingan yang dibahas pada bagian berikutnya, sedangkan baris ketiga adalah salinan yang dibahas setelahnya. Satu deklarasi singkat sudah menyediakan semua anggota tersebut, karena itulah case class menjadi pilihan pertama untuk tipe data pada program Scala.
Kesetaraan struktural antar-instance#
Kesetaraan struktural (structural equality) berarti dua instance dianggap sama apabila seluruh fieldnya bernilai sama, tanpa memandang lokasi keduanya di memori. Operator == pada case class memanggil equals yang dihasilkan compiler dan membandingkan field per field. Kelas biasa yang tidak menimpa equals berperilaku berbeda, yaitu membandingkan identitas referensi, sehingga dua objek dengan isi identik belum tentu dianggap sama.
Pada keluaran program sebelumnya, m1 == m2 bernilai true meskipun keduanya dibuat dari dua ekspresi yang berbeda, karena isi ketiga fieldnya sama. Sebaliknya, m1 == m3 bernilai false karena field quantity-nya berbeda, yaitu 4 dan 7. Perbandingan semacam ini berlaku untuk seluruh field yang dideklarasikan pada parameter utama, sedangkan anggota yang didefinisikan di dalam tubuh kelas tidak ikut dibandingkan.
copy untuk salinan dengan sebagian perubahan#
Metode copy membuat instance baru yang field-fieldnya disalin dari instance sumber, kecuali field yang diganti melalui argumen bernama. Instance sumber tidak tersentuh sama sekali, sehingga variasi data dinyatakan sebagai data baru alih-alih mengubah data yang lama. Cara ini sesuai dengan sifat immutable case class, dan salinannya dapat digunakan bersama kode lain tanpa menimbulkan efek samping.
Pada program sebelumnya, m1.copy(quantity = 7) menghasilkan LabItem(Mikroskop,MIK-01,7). Field name dan code disalin apa adanya dari m1, sedangkan quantity diganti sesuai argumennya. Jumlah argumen pada copy boleh kurang dari jumlah field, sehingga satu field dapat diubah tanpa menulis ulang argumen yang lain.
Destructuring dengan pola val#
Destructuring adalah pembongkaran nilai menjadi beberapa pengikat sekaligus, dan case class mendukungnya karena objek companion-nya mendapat metode unapply. Pola val LabItem(name, code, quantity) memanggil ekstraktor itu lalu mengikat setiap field ke nama lokal yang ditentukan pengembang. Bentuk ini menghilangkan rangkaian akses field berulang, terutama ketika seluruh field memang dibutuhkan.
Program berikut memilih alat dengan stok terkecil dari tiga catatan inventaris menggunakan minBy, kemudian membongkar hasilnya untuk menyusun pesan pemesanan ulang.
// case class alat laboratorium beserta destructuring-nya
case class LabItem(name: String, code: String, quantity: Int)
@main def lowStock(): Unit =
val items = Vector(
LabItem("Mikroskop", "MIK-01", 4),
LabItem("Buret", "BRT-02", 12),
LabItem("Spektrofotometer", "SPF-03", 2)
)
// metode minBy memilih elemen dengan quantity terkecil
val critical = items.minBy(_.quantity)
// destructuring: pola val mengikat setiap field ke nama lokal
val LabItem(name, code, quantity) = critical
println(s"Pesan ulang: $name ($code), sisa $quantity")# menjalankan program lab-destructure.scala
scala-cli run lab-destructure.scalaPesan ulang: Spektrofotometer (SPF-03), sisa 2Keluaran memperlihatkan hasil pemilihan beserta isi fieldnya dalam satu kalimat terformat. Nama lokal name, code, dan quantity hanya berlaku pada lingkup setelah pola tersebut, sehingga program tetap ringkas tanpa variabel sementara tambahan. Pola yang sama juga dapat ditulis di dalam for dan pencocokan pola (pattern matching) yang menggunakan unapply yang sama.
Kapan case class dipilih#
Pemilihan antara case class, kelas biasa, dan trait dapat diringkas sebagai berikut.
| Kebutuhan | Pilihan yang sesuai |
|---|---|
| Data dengan kesetaraan menurut isi dan field yang tetap | case class |
| Objek dengan identitas tersendiri atau state yang berubah | kelas biasa |
| Kontrak perilaku atau implementasi yang dibagikan | trait |
Case class cocok untuk data domain seperti catatan inventaris, hasil pengukuran, atau baris laporan, karena nilainya dibandingkan dan didistribusikan apa adanya. Kelas biasa lebih tepat ketika identitas objek lebih penting daripada isinya, misalnya penampung atau antrean yang state internalnya berubah sepanjang waktu. Trait dipilih ketika yang dibagikan adalah perilaku, bukan data. Ketiganya saling melengkapi, dan deklarasi case class pun dapat mewarisi trait seperti kelas biasa, sehingga data dan perilaku tetap dapat dipisahkan dengan rapi.
Ringkasan#
- Parameter case class otomatis menjadi field immutable, sedangkan compiler menghasilkan
apply,toString,equals,hashCode,copy, danunapplypada objek companion-nya. - Operator
==membandingkan isi field per field, sehingga dua instance dengan data yang sama dianggap sama dan aman digunakan sebagai kunciMap. - Metode
copymembuat instance baru dengan sebagian field diganti melalui argumen bernama, sementara instance sumber tetap utuh. - Pola
valpada destructuring menggunakanunapplyuntuk mengikat setiap field ke nama lokal tanpa variabel sementara.
Referensi#
- Case Classes — Scala Documentation
— Halaman resmi yang merangkum anggota otomatis case class, termasuk kesetaraan struktural dan
copy. - Case Classes and Case Objects — Scala 3 Book — Bab buku resmi Scala 3 yang memperkenalkan case class untuk pemodelan data immutable.