Groovy menyediakan tiga struktur data yang ditulis langsung sebagai literal, yaitu list, map, dan range. Topik ini membahas sintaks literal ketiganya, cara mengakses elemen melalui subscripting, serta operator spread yang menerapkan satu panggilan metode pada seluruh elemen sekaligus. Setelah membaca topik ini, pemilihan struktur data untuk kebutuhan umum beserta cara membaca dan mengubah isinya dapat dilakukan tanpa mendeklarasikan kelas tambahan apa pun.
List dan akses elemennya#
Literal list ditulis sebagai tanda kurung siku yang memuat elemen-elemennya, dan Groovy mengubahnya menjadi java.util.ArrayList secara otomatis. Tidak ada deklarasi tipe yang wajib, sehingga satu list boleh memuat campuran tipe nilai. Elemen diakses dengan subscripting, yakni notasi kurung siku yang menyebut posisi elemen. Indeks negatif dihitung dari belakang, sehingga indeks -1 selalu menunjuk elemen terakhir. Kurung siku juga menerima range, dan bentuk ini menghasilkan sublist sesuai batas rentangnya.
Berkas berikut memuat operasi list yang paling sering dipakai, mulai dari pembacaan elemen hingga penambahan elemen dengan operator <<.
// List Groovy: literal, subscripting, dan penambahan elemen
def ganjil = [1, 3, 5, 7]
println "Awal : $ganjil"
println "Pertama : ${ganjil[0]}"
println "Terakhir : ${ganjil[-1]}"
println "Rentang idx: ${ganjil[1..2]}"
println "Banyaknya : ${ganjil.size()}"
ganjil << 9
println "Setelah << : $ganjil"
println "Berisi 5 : ${ganjil.contains(5)}"
println "Tipe : ${ganjil.getClass().simpleName}"Awal : [1, 3, 5, 7]
Pertama : 1
Terakhir : 7
Rentang idx: [3, 5]
Banyaknya : 4
Setelah << : [1, 3, 5, 7, 9]
Berisi 5 : true
Tipe : ArrayListKeluaran di atas menunjukkan tiga perilaku penting. Pertama, ganjil[1..2] menghasilkan list baru berisi elemen posisi 1 sampai 2, yaitu [3, 5], tanpa mengubah list aslinya. Kedua, operator << menambahkan elemen pada akhir list secara langsung, sehingga ganjil berubah menjadi [1, 3, 5, 7, 9]. Ketiga, metode contains memeriksa keanggotaan dan mengembalikan nilai boolean. List kosong ditulis [] dan tetap berstatus List yang sah, seperti diperlihatkan potongan berikut.
def daftarKosong = []
def petaKosong = [:]
println daftarKosong instanceof List
println petaKosong instanceof Map
println daftarKosong.size()
println petaKosong.size()true
true
0
0Map dan akses kuncinya#
Literal map ditulis dengan pasangan kunci: nilai di dalam kurung siku, dan Groovy menyimpannya sebagai LinkedHashMap yang menjaga urutan penyisipan. Kunci pada literal yang ditulis tanpa tanda kutip diubah menjadi String, sehingga [Ali: 90] sama saja dengan ['Ali': 90]. Ada dua cara membaca nilai, yaitu subscripting dengan kunci di dalam kurung siku atau akses titik sebagaimana akses properti. Penulisan kunci baru melalui subscripting langsung menambahkan entri.
// Map Groovy: literal, akses kunci, dan penambahan entri
def nilai = [Ali: 90, Budi: 75, Citra: 88]
println "Nilai Ali : ${nilai['Ali']}"
println "Nilai Budi: ${nilai.Budi}"
println "Jumlah : ${nilai.size()}"
nilai['Dewi'] = 82
println "Setelah : $nilai"
println "Belum ada : ${nilai['Fajar']}"
println "Kunci saja: ${nilai.keySet()}"Nilai Ali : 90
Nilai Budi: 75
Jumlah : 3
Setelah : [Ali:90, Budi:75, Citra:88, Dewi:82]
Belum ada : null
Kunci saja: [Ali, Budi, Citra, Dewi]Perhatikan baris kelima pada keluaran. Pembacaan kunci yang belum ada menghasilkan null, bukan error, sehingga pemeriksaan keberadaan entri perlu dilakukan secara eksplisit apabila null juga merupakan nilai yang sah pada data tersebut. Metode keySet mengembalikan seluruh kunci dalam urutan penyisipannya.
Range sebagai urutan beraturan#
Range adalah urutan nilai beraturan yang ditulis dengan dua titik, misalnya 1..5 untuk bilangan dari 1 sampai 5 secara inklusif. Bentuk 1..<5 mengecualikan batas atasnya, sedangkan 5..1 menghasilkan urutan menurun. Groovy mengimplementasikan range sebagai IntRange untuk bilangan bulat, dan range berperilaku seperti Iterable, sehingga sebagian besar metode list dapat dipakai padanya. Properti from dan to membaca batasnya, metode step mengambil elemen dengan jarak tetap, dan metode toList mengubahnya menjadi list biasa.
// Range Groovy: batas, langkah, dan urutan turun
def harfi = 'a'..'e'
println harfi
println harfi.toList()
println harfi.from
println harfi.to
println((1..10).step(3))
println((5..1).toList())
println harfi.contains('c')a..e
[a, b, c, d, e]
a
e
[1, 4, 7, 10]
[5, 4, 3, 2, 1]
truePencetakan langsung menampilkan notasi rentangnya, yaitu a..e, sedangkan toList() memperlihatkan isi urutannya secara lengkap. Keluaran (1..10).step(3) berupa [1, 4, 7, 10] karena langkah tiga dimulai dari batas bawah. Range huruf seperti 'a'..'e' juga sah karena karakter memiliki urutan yang terdefinisi.
Operator spread#
Operator spread ditulis *. dan berfungsi memanggil satu metode atau properti pada setiap elemen agregat, lalu mengumpulkan hasilnya menjadi list baru. Ekspresi kata*.toUpperCase() setara dengan kata.collect { it.toUpperCase() }, tetapi bentuk spread lebih ringkas untuk kasus sederhana. Operator ini bersifat null-safe, artinya elemen null di dalam list tidak memicu NullPointerException dan hasilnya tetap berupa null pada posisi tersebut.
// Operator spread: satu metode untuk seluruh elemen
def kata = ['jeruk', 'apel', 'kiwi']
println "Kapital : ${kata*.toUpperCase()}"
println "Panjang : ${kata*.length()}"
def campur = ['Ali', null, 'Budi']
println "Null-safe: ${campur*.toUpperCase()}"Kapital : [JERUK, APEL, KIWI]
Panjang : [5, 4, 4]
Null-safe: [ALI, null, BUDI]Baris ketiga pada keluaran memperlihatkan sifat null-safe tersebut. Elemen null dipetakan menjadi null tanpa menghentikan proses, sehingga operator spread aman dipakai pada data yang belum lengkap. Operator ini berlaku pada setiap kelas yang mengimplementasikan Iterable, termasuk list hasil literal maupun range.
Kesalahan umum#
Kesalahan pertama terjadi saat println diberi literal list tanpa tanda kurung. Parser membaca println [1, 2, 3] sebagai pengindeksan pada nama println, bukan sebagai pemanggilan metode dengan argumen list, sehingga muncul MissingPropertyException saat skrip dijalankan. Pemakaian tanda kurung memperbaikinya.
try {
println [1, 2, 3]
} catch (MissingPropertyException e) {
println "Gagal : ${e.getClass().simpleName}"
}
println([1, 2, 3])Gagal : MissingPropertyException
[1, 2, 3]Kesalahan kedua menyangkut indeks di luar batas. Pembacaan dengan indeks positif yang melebihi ukuran list menghasilkan null tanpa pemberitahuan, sedangkan indeks negatif yang melewati elemen pertama melempar ArrayIndexOutOfBoundsException. Perbedaan ini sering menyembunyikan cacat data karena sisi yang tidak melempar error tidak menampilkan apa pun pada keluaran.
def nilai = [70, 80, 90]
println "Indeks 5 : ${nilai[5]}"
try {
println nilai[-5]
} catch (ArrayIndexOutOfBoundsException e) {
println "Gagal : ${e.getClass().simpleName}"
}Indeks 5 : null
Gagal : ArrayIndexOutOfBoundsExceptionKesalahan ketiga adalah mengandalkan data.class untuk mengambil tipe objek dari sebuah map. Karena akses titik pada map memeriksa kuncinya lebih dahulu, ekspresi tersebut menghasilkan nilai kunci class apabila ada, atau null apabila tidak ada. Metode getClass() adalah cara yang benar.
def data = [nama: 'Ali']
println data.class
println data.getClass().simpleName
println data['class']null
LinkedHashMap
nullRingkasan#
- Literal
[...]menghasilkanArrayList, literal[kunci: nilai]menghasilkanLinkedHashMapyang menjaga urutan penyisipan, dana..bmenghasilkanIntRange. - Subscripting menerima indeks negatif dan range, sehingga
list[-1]membaca elemen terakhir danlist[1..2]menghasilkan sublist. - Operator
*.memanggil satu metode untuk setiap elemen dan bersifat null-safe terhadap elemennull. printlndengan argumen literal list wajib diberi tanda kurung agar tidak ditafsirkan sebagai pengindeksan.
Referensi#
- Documentation (panduan bahasa lengkap) — Apache Groovy — bab Working with collections menjelaskan literal list, map, range, serta sifat spread operator.
- Operators — Apache Groovy
— bagian spread operator memuat kesetaraan dengan
collectdan perilaku null-safe-nya.