Setelah mempelajari semua jenis collection dan operasinya, pertanyaan yang muncul adalah: untuk masalah tertentu, collection mana yang sebaiknya dipilih? Pilihan yang tepat membuat kode lebih jelas, lebih aman, dan lebih cepat. Pada chapter ini kita akan merangkum panduan praktis dalam bentuk decision tree dan tabel perbandingan, lalu menerapkannya pada delapan skenario konkret yang sering dijumpai di aplikasi nyata.

Decision Tree Memilih Collection #

Berikut panduan praktis memilih collection berdasarkan kebutuhan:

KebutuhanPilihanAlasan
Urutan penting, duplikat wajarListBerurutan, menerima duplikat, akses indeks O(1)
Elemen harus unikSetMenolak duplikat, cek keanggotaan cepat
Pasangan key-value, lookup cepatMapAkses O(1) berdasarkan key
Ukuran tetap, tipe primitif, hot pathIntArray / LongArray / dll.Tanpa boxing, memori efisien
Interop Java varargs T[]Array<T>Tipe array objek Java
Pipeline panjang + koleksi besarSequenceLazy evaluation, short-circuit
Perlu add/remove saat runtimeMutableList / MutableSet / MutableMapMutasi terkendali

Pertanyaan Pertama: Apakah Perlu Mutasi? #

Pertanyaan paling penting adalah apakah collection akan dimodifikasi setelah dibuat. Default gunakan read-only (List, Set, Map). Hanya bila mutasi benar-benar diperlukan, gunakan variant mutable.

Varian Read-OnlyVarian MutableOperasi Mutasi
List<T>MutableList<T>add, removeAt, set
Set<T>MutableSet<T>add, remove
Map<K, V>MutableMap<K, V>put, remove, compute

Pertanyaan Kedua: Tipe Data Apa? #

  • Objek (String, data class, Int?): gunakan List<T> / MutableList<T>.
  • Primitif numerik dalam jumlah besar atau hot path: gunakan IntArray / LongArray / DoubleArray / dll.
  • Interoperabilitas Java: gunakan Array<T> untuk T[] Java atau array primitif untuk int[].

Pertanyaan Ketiga: Pola Akses? #

  • Akses berbasis indeks (coll[i]): List (acak O(1)).
  • Akses berbasis key: Map (O(1) rata-rata).
  • Cek keanggotaan: Set (O(1) rata-rata, lebih cepat dari List.contains).
  • Iterasi sekali, lazy: Sequence (hemat alokasi pada pipeline panjang).

Contoh Lengkap #

kotlin
data class Produk(val nama: String, val kategori: String, val harga: Int, val stok: Int)

fun main() {
    // === Skenario 1: Daftar urutan transaksi ===
    // List cocok karena: urutan penting, duplikat wajar, akses indeks
    val antrianPesanan = listOf("P001", "P002", "P003", "P002", "P004")
    println("Antrian pesanan: $antrianPesanan")
    println("Pesanan pertama: ${antrianPesanan.first()}")
    println("Jumlah total: ${antrianPesanan.size}")

    // === Skenario 2: Daftar ID unik pengguna ===
    // Set cocok karena: tidak boleh ada duplikat
    val idPengguna = setOf("U001", "U002", "U003", "U001")
    println("ID pengguna unik: ${idPengguna.sorted()}")
    println("Jumlah pengguna unik: ${idPengguna.size}")

    // === Skenario 3: Pemetaan kode produk ke stok ===
    // Map cocok karena: lookup berdasarkan key, key unik
    val stokProduk = mapOf(
        "K001" to 50,
        "K002" to 30,
        "K003" to 75
    )
    println("Stok K002: ${stokProduk["K002"]}")
    println("Semua kode: ${stokProduk.keys.sorted()}")

    // === Skenario 4: Data kuantitatif besar (suhu sensor) ===
    // Array primitif cocok karena: ukuran tetap, tipe primitif, hot path
    val suhuSensor = doubleArrayOf(36.5, 36.7, 36.6, 36.8, 36.5, 36.7)
    println("Suhu rata-rata: ${suhuSensor.average()}")
    println("Suhu maks: ${suhuSensor.maxOrNull()}")

    // === Skenario 5: Build collection sementara ===
    // MutableList cocok karena: perlu add/remove saat build
    val tagDipilih = mutableListOf<String>()
    tagDipilih.add("kotlin")
    tagDipilih.add("jvm")
    tagDipilih.add("backend")
    println("Tag: $tagDipilih")

    // === Skenario 6: Cache nilai yang dihitung ===
    // MutableMap cocok karena: tambah/update value seiring waktu
    val cache = mutableMapOf<String, Int>()
    val panjang = cache.getOrPut("kotlin") { "kotlin".length }
    println("Cache panjang \"kotlin\": $panjang")
    println("Isi cache: $cache")

    // === Skenario 7: Interop dengan API Java varargs ===
    // Array cocok karena: Java varargs memerlukan T[]
    fun jumlahkan(vararg x: Int): Int = x.sum()
    val argumen = arrayOf(1, 2, 3, 4, 5)
    val total = jumlahkan(*argumen.toIntArray())
    println("Total dari array Java: $total")

    // === Skenario 8: Pipeline panjang dengan take awal ===
    // Sequence cocok karena: lazy, short-circuit, koleksi besar
    val data = (1..1_000_000).toList()
    val limaKuadrat = data
        .asSequence()
        .map { it * it }
        .filter { it > 10 }
        .take(5)
        .toList()
    println("Lazy pipeline: $limaKuadrat")

    // === Decision Tree Ringkas ===
    println("--- Decision Tree ---")
    println("Butuh akses indeks O(1)?                -> List")
    println("Butuh duplikat?                         -> List")
    println("Butuh keunikan elemen?                  -> Set")
    println("Pasangan key-value?                     -> Map")
    println("Ukuran tetap, tipe primitif, hot path? -> IntArray/LongArray/...")
    println("Interop Java varargs?                   -> Array<T>")
    println("Pipeline panjang + koleksi besar?       -> Sequence")
    println("Koleksi perlu diubah?                   -> Mutable variant")
}

Output yang Dihasilkan:

text
Antrian pesanan: [P001, P002, P003, P002, P004]
Pesanan pertama: P001
Jumlah total: 5
ID pengguna unik: [U001, U002, U003]
Jumlah pengguna unik: 3
Stok K002: 30
Semua kode: [K001, K002, K003]
Suhu rata-rata: 36.63333333333333
Suhu maks: 36.8
Tag: [kotlin, jvm, backend]
Cache panjang "kotlin": 6
Isi cache: {kotlin=6}
Total dari array Java: 15
Lazy pipeline: [16, 25, 36, 49, 64]
--- Decision Tree ---
Butuh akses indeks O(1)?                -> List
Butuh duplikat?                         -> List
Butuh keunikan elemen?                  -> Set
Pasangan key-value?                     -> Map
Ukuran tetap, tipe primitif, hot path? -> IntArray/LongArray/...
Interop Java varargs?                   -> Array<T>
Pipeline panjang + koleksi besar?       -> Sequence
Koleksi perlu diubah?                   -> Mutable variant

Mari kita bedah pemilihan collection pada skenario-skenario di atas:

  1. Skenario 1 (antrian pesanan): List dipilih karena pesanan boleh berulang (ID "P002" muncul dua kali) dan urutan transaksi penting. Set akan membuang duplikat — bukan yang kita inginkan di sini.
  2. Skenario 2 (ID pengguna unik): Set dipilih karena ID tidak boleh ada duplikat. Pemanggilan setOf("U001", ..., "U001") hanya menyimpan satu "U001".
  3. Skenario 3 (stok per kode): Map dipilih karena kita mencari stok berdasarkan kode produk. Akses stokProduk["K002"] adalah O(1), jauh lebih cepat daripada mencari di list of pairs.
  4. Skenario 4 (suhu sensor): DoubleArray dipilih karena data numerik kontinu, ukuran tetap (jumlah sensor), dan sering dipakai dalam perhitungan (average, max). Boxing pada List<Double> akan boros memori.
  5. Skenario 5 (tag dipilih): MutableList dipilih karena kita membangun list secara bertahap dari input pengguna. Bila tag harus unik, gunakan MutableSet sebagai gantinya.
  6. Skenario 6 (cache): MutableMap dipilih karena kita menambah dan memperbarui key-value seiring waktu. getOrPut adalah idiom kanonik untuk cache — lambda hanya dievaluasi saat key belum ada.
  7. Skenario 7 (varargs Java): Array<Int> dipilih karena API Java vararg memerlukan int[]. Karena signature fungsi adalah vararg Int, kita perlu mengonversi Array<Int> ke IntArray lebih dulu dengan toIntArray().
  8. Skenario 8 (pipeline panjang): Sequence dipilih karena koleksi berukuran satu juta dan kita hanya butuh 5 elemen hasil. Lazy evaluation berhenti setelah 5 elemen terkumpul, menghindari alokasi list antara yang besar.

Tabel Ringkas Komparatif #

AspekListSetMapArrayPrimitive ArraySequence
DuplikatYaTidakKey unikYaYaYa
UrutanBerurutanTidak (default)PenyisipanBerurutanBerurutanSesuai sumber
Akses indeks O(1)YaTidakKey O(1)YaYaTidak
Ukuran tetapTidak (mutable)Tidak (mutable)Tidak (mutable)YaYaLazy
Mutasi elemenMutable varMutable varMutable varYaYaTidak
BoxingYa/BebasYa/BebasYa/BebasYaTidakYa/Bebas
Cocok untukDaftar urutanKeunikanLookup keyInteropHot path numerikPipeline panjang

Referensi Lanjutan #

  • Collections overview — tinjauan umum untuk memilih List, Set, Map
  • Set — kapan memakai Set untuk keunikan elemen
  • Map — kapan memakai Map untuk lookup key

Dengan panduan ini, kita siap memilih collection yang tepat untuk berbagai skenario yang akan ditemui dalam pengembangan aplikasi Kotlin. Section Collections selesai, dan kita akan melanjutkan ke topik lanjutan berikutnya pada section selanjutnya.