List read-only membatasi kita pada operasi baca. Begitu kebutuhan berubah menjadi menambah, mengganti, atau menghapus elemen, kita beralih ke MutableList<T>. Interface ini menambah metode mutasi pada List<T> sambil tetap menyediakan semua operasi baca. Pada chapter ini kita akan menjelajahi operasi mutasi utama, urutan eksekusinya, dan jebakan ketika list mutable dipakai di lingkungan multi-thread.
Membuat MutableList #
MutableList dibuat menggunakan mutableListOf(...). Tipe elemen disimpulkan dari argumen pertama.
val antrian: MutableList<String> = mutableListOf("A", "B", "C")
val angka = mutableListOf(1, 2, 3) // MutableList<Int>
val kosong = mutableListOf<Double>() // MutableList<Double> kosongSejak list ini mutable, kita bebas menambah, menyisipkan, mengganti, dan menghapus elemen selama program berjalan.
Operasi Mutasi Dasar #
| Metode | efek | Contoh |
|---|---|---|
add(x) | menambah elemen di akhir | tugas.add("Olahraga") |
add(i, x) | menyisipkan elemen di indeks i | tugas.add(1, "Masak") |
set(i, x) | mengganti elemen di indeks i | tugas[2] = "Cuci Mobil" |
remove(x) | menghapus kemunculan pertama x | tugas.remove("Baca Buku") |
removeAt(i) | menghapus elemen pada indeks i | tugas.removeAt(0) |
addAll(c) | menambah semua elemen collection lain | tugas.addAll(listOf(...)) |
clear() | mengosongkan list | tugas.clear() |
Metode remove(x) mengembalikan Boolean — true bila elemen benar-benar dihapus, false bila elemen tidak ditemukan. removeAt(i) mengembalikan elemen yang dihapus; metode ini melempar IndexOutOfBoundsException jika indeks tidak valid.
Contoh Lengkap #
Mari kita rangkai semua operasi dalam satu program:
fun main() {
val tugas = mutableListOf("Belanja", "Cuci Motor", "Baca Buku")
println("Awal: $tugas")
// Menambah elemen
tugas.add("Olahraga")
println("Setelah add: $tugas")
// Menambah di indeks tertentu
tugas.add(1, "Masak")
println("Setelah add(1, ...): $tugas")
// Mengganti elemen
tugas[2] = "Cuci Mobil"
println("Setelah set indeks 2: $tugas")
// Menghapus
tugas.remove("Baca Buku")
println("Setelah remove(\"Baca Buku\"): $tugas")
tugas.removeAt(0)
println("Setelah removeAt(0): $tugas")
// Operasi batch
tugas.addAll(listOf("Belajar Kotlin", "Tidur"))
println("Setelah addAll: $tugas")
// Iterasi dengan indeks
println("Daftar tugas:")
tugas.forEachIndexed { i, item -> println(" ${i + 1}. $item") }
// Sublist (view)
val duaPertama = tugas.subList(0, 2)
println("SubList(0,2): $duaPertama")
// Clear semua
val sementara = mutableListOf("a", "b", "c")
println("Sementara sebelum clear: $sementara")
sementara.clear()
println("Sementara setelah clear: $sementara, isEmpty=${sementara.isEmpty()}")
// Catatan thread safety
println("List mutable TIDAK aman untuk akses multi-thread tanpa sinkronisasi")
}Output yang Dihasilkan:
Awal: [Belanja, Cuci Motor, Baca Buku]
Setelah add: [Belanja, Cuci Motor, Baca Buku, Olahraga]
Setelah add(1, ...): [Belanja, Masak, Cuci Motor, Baca Buku, Olahraga]
Setelah set indeks 2: [Belanja, Masak, Cuci Mobil, Baca Buku, Olahraga]
Setelah remove("Baca Buku"): [Belanja, Masak, Cuci Mobil, Olahraga]
Setelah removeAt(0): [Masak, Cuci Mobil, Olahraga]
Setelah addAll: [Masak, Cuci Mobil, Olahraga, Belajar Kotlin, Tidur]
Daftar tugas:
1. Masak
2. Cuci Mobil
3. Olahraga
4. Belajar Kotlin
5. Tidur
SubList(0,2): [Masak, Cuci Mobil]
Sementara sebelum clear: [a, b, c]
Sementara setelah clear: [], isEmpty=true
List mutable TIDAK aman untuk akses multi-thread tanpa sinkronisasiMari kita bedah baris-baris penting di atas:
tugas.add(1, "Masak"): elemen"Masak"disisipkan pada indeks1; elemen yang sebelumnya berada di indeks1dan setelahnya bergeser ke kanan.tugas[2] = "Cuci Mobil": subscript di sisi penugasan menjalankanset(2, "Cuci Mobil"), mengganti elemen pada indeks2.tugas.remove("Baca Buku"): pencarian linear dimulai dari indeks0. Hanya kemunculan pertama yang dihapus; sisanya tetap utuh bila ada.tugas.subList(0, 2): mengembalikan view — bukan salinan. Perubahan pada sublist akan terlihat pada list asli dan sebaliknya.sementara.clear(): menghapus semua elemen dan mengatursizemenjadi0; kapasitas internal tidak dijamin berubah.
Catatan Konkurensi #
MutableList dari mutableListOf tidak aman untuk akses paralel. Jika dua thread memanggil add secara bersamaan tanpa sinkronisasi, kita berisiko mendapat data terkorup atau ConcurrentModificationException.
Untuk skenario multi-thread, pilih alternatif berikut:
Collections.synchronizedList(mutableListOf(...))— membungkus list dengan sinkronisasi method-level.CopyOnWriteArrayList— aman untuk iterasi paralel dengan biaya salinan pada setiap mutasi.- Channel atau actor — membatasi mutasi ke satu thread dan mengirim permintaan perubahan melalui pesan.
Referensi Lanjutan #
- MutableList API reference
— API reference
kotlin.collections.MutableList - ArrayList API reference
— API reference
kotlin.collections.ArrayList - Collection write operations
— panduan
add,remove,set,clear
Dengan kemampuan mutasi MutableList di tangan, kita beranjak ke collection yang menolak duplikat: Set.