Collection adalah struktur data yang menyimpan banyak nilai sekaligus. Kotlin memetakan collection ke sebuah hierarki interface yang berasal dari pustaka standar, sehingga setiap fungsi bisa beroperasi pada banyak jenis collection sekaligus. Pada chapter ini kita akan menelusuri hierarki tersebut, mulai dari akar Iterable<T> hingga cabang List, Set, dan Map. Kita juga akan membedakan interface read-only dengan interface mutable dan memahami implikasi pemilihannya terhadap keamanan kode.
Akar Hierarki: Iterable dan Collection #
Semua collection di Kotlin berakar pada interface Iterable<T>. Interface ini hanya menyatakan satu kemampuan: koleksi tersebut dapat diiterasi melalui iterator. Turunan langsungnya adalah Collection<T>, yang menambah operasi seperti size, contains, dan isEmpty. Karena Iterable dan Collection bersifat read-only, kedua interface ini tidak memiliki metode untuk menambah, mengubah, atau menghapus elemen.
Dari Collection<T> lahir dua cabang utama:
| Interface | Kontrak Utama | Contoh Konkret |
|---|---|---|
List<T> | Berurutan, menerima duplikat, akses indeks | listOf(1, 2, 3) |
Set<T> | Tidak menerima duplikat, tanpa jaminan urutan | setOf("a", "b") |
Map<K, V> tidak mewarisi Collection<T> karena menyimpan pasangan key-value, bukan nilai tunggal. Meskipun demikian, Map tetap dianggap bagian dari koleksi pustaka standar Kotlin.
Read-Only vs Mutable #
Setiap interface collection memiliki pasangan mutable:
List<T>→MutableList<T>menambahadd,removeAt,set.Set<T>→MutableSet<T>menambahadd,remove.Map<K, V>→MutableMap<K, V>menambahput,remove,clear.
Pemisahan ini memungkinkan kita menyimpan referensi read-only ke collection yang sebenarnya mutable. Pola umum dalam API Kotlin adalah menerima parameter List<String> (read-only) tetapi memprosesnya dengan MutableList<String> di internal.
Contoh Kode Konkret #
Mari kita lihat perbedaan keempat collection dasar dalam satu program:
fun main() {
// List read-only dan mutable
val namaHari: List<String> = listOf("Senin", "Selasa", "Rabu")
val namaHariMutable: MutableList<String> = mutableListOf("Senin", "Selasa", "Rabu")
println("List read-only: $namaHari")
println("MutableList awal: $namaHariMutable")
namaHariMutable.add("Kamis")
println("MutableList setelah add: $namaHariMutable")
// Set read-only dan mutable
val kodeUnik: Set<Int> = setOf(101, 202, 303)
val kodeUnikMutable: MutableSet<Int> = mutableSetOf(101, 202, 303)
println("Set read-only: ${kodeUnik.sorted()}")
kodeUnikMutable.add(404)
println("MutableSet setelah add: ${kodeUnikMutable.sorted()}")
// Map read-only dan mutable
val ibukota: Map<String, String> = mapOf("Jepang" to "Tokyo", "Korea" to "Seoul")
val ibukotaMutable: MutableMap<String, String> = mutableMapOf("Jepang" to "Tokyo")
println("Map read-only: $ibukota")
ibukotaMutable["Korea"] = "Seoul"
println("MutableMap setelah put: $ibukotaMutable")
// List read-only tetap bisa dibaca, tidak bisa diubah
println("Jumlah hari read-only: ${namaHari.size}")
println("Hari pertama: ${namaHari[0]}")
// Tipe runtime dari listOf adalah ArrayList (mutable di JVM)
println("Runtime type listOf: ${namaHari::class.simpleName}")
println("Runtime type mutableListOf: ${namaHariMutable::class.simpleName}")
}Output yang Dihasilkan:
List read-only: [Senin, Selasa, Rabu]
MutableList awal: [Senin, Selasa, Rabu]
MutableList setelah add: [Senin, Selasa, Rabu, Kamis]
Set read-only: [101, 202, 303]
MutableSet setelah add: [101, 202, 303, 404]
Map read-only: {Jepang=Tokyo, Korea=Seoul}
MutableMap setelah put: {Jepang=Tokyo, Korea=Seoul}
Jumlah hari read-only: 3
Hari pertama: Senin
Runtime type listOf: ArrayList
Runtime type mutableListOf: ArrayListMari kita bedah baris-baris penting program di atas:
val namaHari: List<String>: deklarasi variabel read-only bertipeList<String>. Meskipun objek runtime adalahArrayList, kompilator hanya mengizinkan operasi yang dideklarasikan padaList.namaHariMutable.add("Kamis"): metodeaddhanya tersedia padaMutableList. Pemanggilan serupa padanamaHariakan ditolak kompilator.kodeUnik.sorted():Settidak memiliki indeks dan tidak menjamin urutan, sehingga untuk hasil deterministik kita urutkan sebelum mencetak.ibukotaMutable["Korea"] = "Seoul": notasi subscript padaMutableMapsetara dengan pemanggilanput("Korea", "Seoul").namaHari::class.simpleName: refleksi tipe runtime membuktikan bahwalistOfmengembalikanArrayListdi JVM, bukan tipe khusus immutable.
Strategi Memilih Interface #
Berikut pedoman praktis memilih interface:
- Default gunakan read-only (
List,Set,Map) untuk parameter fungsi dan properti publik. - Gunakan mutable (
MutableList,MutableSet,MutableMap) hanya ketika kita perlu memodifikasi isi di tempat. - Jika fungsi perlu membangun list sementara, gunakan
mutableListOfdi dalam, lalu kembalikan sebagaiListke pemanggil.
Referensi Lanjutan #
- Collections overview
— panduan resmi hierarki
Iterable,Collection,List,Set,Map - List API reference
— API reference
kotlin.collections.List - Set API reference
— API reference
kotlin.collections.Set
Dengan pemahaman hierarki ini, kita siap membahas komponen pertama secara mendalam: List akan dibahas pada chapter berikutnya.