Generics

List(Of T) dan Dictionary(Of K, V) sebagai koleksi generik utama .NET.

Daftar isi

Koleksi adalah struktur penyimpanan yang banyaknya elemen dapat berubah saat program berjalan, dan topik ini membahas dua koleksi generik utama .NET, yaitu List(Of T) dan Dictionary(Of K, V). Pembahasan dimulai dari kelemahan array berukuran tetap dan ArrayList, dilanjutkan dengan operasi dasar kedua koleksi generik, dan ditutup dengan kesalahan yang sering terjadi. Setelah membacanya, pemilihan koleksi untuk daftar peserta, inventaris, atau pemetaan kunci ke nilai dapat dilakukan dengan alasan yang jelas.

Masalah array dan ArrayList#

Array memiliki ukuran yang ditetapkan saat dibuat dan tidak dapat bertumbuh. Deklarasi Dim stok(4) As Integer menyediakan tepat lima elemen dengan indeks 0 sampai 4, dan penambahan elemen baru menuntut pembuatan array lain yang lebih besar lalu penyalinan isinya. Bentuk ReDim mempermudah langkah itu, tetapi di baliknya tetap membuat array baru, sehingga pertumbuhan yang sering terjadi menjadi boros.

vb
' tidak-dijalankan
Dim stok(4) As Integer ' lima elemen, indeks 0 sampai 4
stok(4) = 10
' stok(5) = 20 ' error saat berjalan: indeks berada di luar batas

ArrayList mengatasi masalah ukuran dengan menyimpan setiap elemen sebagai Object, tipe paling umum di .NET. Karena itu, ArrayList menerima campuran tipe apa pun dan compiler tidak dapat memeriksa kecocokan isinya. Pengambilan kembali nilai menghasilkan Object yang masih harus dikonversi, dan konversi yang keliru baru terlihat saat program berjalan.

vb
' tidak-dijalankan
Dim antre As New ArrayList()
antre.Add("Ali")
antre.Add(30)
' antre(1) bertipe Object, sehingga konversi eksplisit diperlukan
Dim salah As String = DirectCast(antre(1), String)

Kode tersebut lolos kompilasi, tetapi baris konversinya melempar System.InvalidCastException saat program berjalan dengan pesan Unable to cast object of type 'System.Int32' to type 'System.String'. Kedua masalah di atas diselesaikan oleh koleksi generik (generics), yaitu koleksi yang menerima parameter tipe sehingga isinya diperiksa compiler sejak awal.

List(Of T): daftar yang dapat bertumbuh#

List(Of T) adalah daftar yang bertumbuh otomatis dan hanya menyimpan elemen bertipe T. Tipe T dituliskan pada saat deklarasi, misalnya List(Of String) untuk teks dan List(Of Integer) untuk bilangan bulat, sehingga pemanggilan Add dengan tipe lain ditolak compiler. Banyaknya elemen dapat diketahui melalui properti Count, sedangkan elemen dibaca lewat indeks yang dimulai dari nol.

Diagram berikut membandingkan cara ArrayList dan List(Of String) menyimpan isinya.

ArrayListsetiap elemen disimpan sebagai ObjectAli30String di balik ObjectInteger di balik ObjectList(Of String)hanya elemen bertipe String yang diterimaAliCitraDewiStringStringString
ArrayList menyimpan Object, sedangkan List(Of String) hanya menerima elemen bertipe String

Program berikut mengelola daftar peserta pelatihan dengan List(Of String), mulai dari penambahan, pembacaan, penghapusan, sampai penelusurannya.

vb Program.vb
Module Program

    Sub Main()
        Dim peserta As New List(Of String)

        peserta.Add("Ali")
        peserta.Add("Budi")
        peserta.Add("Citra")
        peserta.Add("Dewi")

        Console.WriteLine($"Jumlah peserta: {peserta.Count}")
        Console.WriteLine(peserta(0))
        Console.WriteLine(peserta(2))

        peserta.Remove("Budi")
        Console.WriteLine($"Setelah Remove: {peserta.Count}")
        Console.WriteLine(peserta.Contains("Citra"))

        For Each nama As String In peserta
            Console.WriteLine(nama)
        Next
    End Sub

End Module
text Keluaran
Jumlah peserta: 4
Ali
Citra
Setelah Remove: 3
True
Ali
Citra
Dewi

Keluaran mengikuti urutan operasinya. Add menambah empat peserta sehingga Count melaporkan 4, lalu peserta(0) dan peserta(2) membaca elemen pertama dan ketiga. Remove("Budi") mengurangi isi menjadi 3, dan Contains("Citra") mengembalikan True karena Citra masih terdaftar. Perulangan For Each kemudian menampilkan sisa peserta, yaitu Ali, Citra, dan Dewi, dalam urutan penambahannya.

Langkah praktisnya menggunakan .NET SDK melalui perintah berikut.

bash
# tidak-dijalankan
# membuat proyek console VB.NET baru bernama LatihanKoleksi
dotnet new console -lang VB -o LatihanKoleksi
# mengganti isi Program.vb dengan kode program di atas melalui editor
# masuk ke folder proyek
cd LatihanKoleksi
# mengompilasi dan menjalankan program
dotnet run
text Transkrip terminal
$ dotnet new console -lang VB -o LatihanKoleksi
The template "Console App" was created successfully.

Processing post-creation actions...
Restoring /home/kal/my-project/build-scratch/koleksi-linq__transkrip/LatihanKoleksi/LatihanKoleksi.vbproj:
  Determining projects to restore...
  Restored /home/kal/my-project/build-scratch/koleksi-linq__transkrip/LatihanKoleksi/LatihanKoleksi.vbproj (in 76 ms).
Restore succeeded.


$ cd LatihanKoleksi
$ dotnet run
Jumlah peserta: 4
Ali
Citra
Setelah Remove: 3
True
Ali
Citra
Dewi

Dictionary(Of K, V): peta kunci ke nilai#

Dictionary(Of K, V) menyimpan pasangan kunci dan nilai, dengan K tipe kuncinya dan V tipe nilainya. Kunci harus unik, dan pencarian berdasarkan kunci dilakukan langsung melalui tabel hash tanpa menelusuri seluruh koleksi. Untuk inventaris perpustakaan kelas, kuncinya berupa kategori buku bertipe String dan nilainya berupa jumlah salinan bertipe Integer.

Program berikut mengisi inventaris, membaca nilai lewat TryGetValue, mengubah nilai lewat akses indeks, dan menelusuri seluruh entri.

vb Contoh: Dictionary(Of String, Integer) untuk inventaris
Module DemoDictionary

    Sub Main()
        Dim inventaris As New Dictionary(Of String, Integer)

        inventaris.Add("Novel", 12)
        inventaris.Add("Kamus", 3)
        inventaris.Add("Atlas", 5)

        Dim jumlah As Integer
        If inventaris.TryGetValue("Kamus", jumlah) Then
            Console.WriteLine($"Kamus: {jumlah}")
        End If

        inventaris("Atlas") = 7
        Console.WriteLine(inventaris("Atlas"))

        If inventaris.TryGetValue("Majalah", jumlah) Then
            Console.WriteLine(jumlah)
        Else
            Console.WriteLine("Majalah tidak terdaftar")
        End If

        For Each entri As KeyValuePair(Of String, Integer) In inventaris
            Console.WriteLine($"{entri.Key}: {entri.Value}")
        Next
    End Sub

End Module
text Keluaran
Kamus: 3
7
Majalah tidak terdaftar
Novel: 12
Kamus: 3
Atlas: 7

Metode TryGetValue menerima kunci beserta variabel penampung, lalu mengembalikan True bila kuncinya terdaftar dan mengisi variabel tersebut dengan nilainya. Penugasan inventaris("Atlas") = 7 memperbarui nilai kunci yang sudah ada menjadi 7, sedangkan pencarian kunci Majalah yang belum terdaftar mengembalikan False sehingga cabang Else berjalan. Perulangan For Each menyajikan setiap entri sebagai KeyValuePair(Of String, Integer), dan properti Key serta Value mengembalikan kedua bagian pasangannya.

Kesalahan umum#

Tiga kesalahan berikut paling sering muncul saat menggunakan koleksi generik. Ketiganya dapat dihindari dengan kebiasaan penulisan yang sederhana.

  1. Menggunakan koleksi tanpa New. Deklarasi Dim daftar As List(Of String) tanpa instansiasi menghasilkan Nothing, sehingga pemanggilan Add pertama memicu NullReferenceException saat program berjalan. Perbaikannya adalah menuliskan New List(Of String) pada deklarasi.
  2. Menambahkan kunci yang sudah ada dengan Add. Metode ini menolak kunci ganda dengan melempar ArgumentException, sedangkan penugasan inventaris("Kamus") = 4 memperbarui nilai kunci yang sudah terdaftar tanpa error.
  3. Mengubah isi koleksi saat For Each sedang menelusurinya. Penambahan atau penghapusan di tengah penelusuran memicu InvalidOperationException, dan perbaikannya adalah mengumpulkan elemen yang akan dihapus pada daftar terpisah, lalu menghapusnya setelah perulangan selesai.

Ringkasan#

  • Array berukuran tetap dan ArrayList menyimpan nilai tanpa pemeriksaan tipe yang memadai, sehingga koleksi generik menjadi pilihan utama untuk data yang bertumbuh.
  • List(Of T) menyimpan daftar bertipe yang bertumbuh otomatis, dengan Add, Remove, Contains, akses indeks, dan Count sebagai operasi utamanya.
  • Dictionary(Of K, V) memetakan kunci unik ke nilai, dan TryGetValue menjadi cara aman untuk membaca kunci yang keberadaannya belum pasti.
  • Tipe pada parameter Of T diperiksa compiler, sehingga kesalahan tipe tertangkap sebelum program berjalan.

Referensi#