Jumlah argumen sebuah metode biasanya tetap sejak deklarasi, tetapi ada kasus yang menuntut kebebasan: menjumlahkan sekelompok angka, menggabungkan beberapa teks, atau menghitung rata-rata nilai yang jumlahnya baru diketahui saat pemanggilan. Varargs menjawab kebutuhan itu dengan satu parameter yang menerima sejumlah argumen sekaligus. Topik ini membahas sintaksnya, wujud sebenarnya di dalam metode, cara pemanggilannya, dan jebakan yang menyertainya.
Sintaks varargs#
Parameter varargs ditulis dengan tiga titik setelah tipenya, misalnya double... angka. Dari seluruh parameter sebuah metode, varargs hanya boleh ada satu dan wajib berada di posisi terakhir. Aturan ini lahir dari cara kompilator membaca pemanggilan, yaitu ia harus tahu batas pasti antara parameter tetap dan argumen yang menumpuk di belakangnya.
// tidak-dijalankan
static void salah(int... angka, String label) { } // varargs wajib paling akhir
static void salahJuga(int... a, int... b) { } // hanya satu parameter varargsBila aturan itu dilanggar, kompilator berhenti dengan kesalahan pada baris deklarasinya, bukan pada pemanggilannya. Bentuk yang sah memisahkan parameter tetap di depan lalu menaruh varargs di ujung, misalnya gabung(String pemisah, String... teks). Dengan bentuk itu, argumen pertama selalu jadi pemisah, sedangkan sisanya dikumpulkan menjadi satu larik teks.
Di dalam metode, varargs adalah array#
Kompilator menurunkan setiap parameter varargs menjadi parameter array bertipe sama. Di dalam tubuh metode, angka bertipe double[] dan dipakai seperti array biasa, yaitu dibaca length-nya, diindeks, atau dilalui dengan for-each.
public class RingkasanAngka {
static double total(double... angka) {
double jumlah = 0;
for (double a : angka) {
jumlah += a;
}
return jumlah;
}
static double rataRata(double... angka) {
return total(angka) / angka.length;
}
public static void main(String[] args) {
System.out.println("total(2, 3) = " + total(2, 3));
System.out.println("total(1, 2, 3, 4) = " + total(1, 2, 3, 4));
System.out.println("rataRata(8, 9, 10) = " + rataRata(8, 9, 10));
System.out.println("rataRata() = " + rataRata());
}
}total(2, 3) = 5.0
total(1, 2, 3, 4) = 10.0
rataRata(8, 9, 10) = 9.0
rataRata() = NaNPemanggilan total(2, 3) membuat kompilator menyusun array baru berisi 2.0 dan 3.0, lalu menyerahkannya ke metode. Pemanggilan rataRata() tanpa satu argumen pun tetap sah, dan parameternya menjadi array kosong dengan length bernilai 0. Karena pembilangnya 0.0 dan penyebutnya 0 pada aritmetika double, hasilnya NaN.
Memanggil dengan array atau tanpa argumen#
Karena varargs adalah array, pemanggil boleh mengirim array yang sudah jadi sebagai ganti daftar argumen lepas. Sebaliknya tidak berlaku: parameter bertipe array wajib menerima array dan tidak bisa dipanggil dengan argumen terpisah.
public class PadananArray {
static int totalVarargs(int... angka) {
return jumlahkan(angka);
}
static int totalArray(int[] angka) {
return jumlahkan(angka);
}
static int jumlahkan(int[] angka) {
int jumlah = 0;
for (int a : angka) {
jumlah += a;
}
return jumlah;
}
public static void main(String[] args) {
System.out.println(totalVarargs(1, 2, 3));
System.out.println(totalVarargs(new int[] {4, 5}));
System.out.println(totalArray(new int[] {6, 7, 8}));
}
}6
9
21Ketiga pemanggilan menghasilkan total yang benar melalui jalur berbeda. totalVarargs(1, 2, 3) memakai argumen lepas, totalVarargs(new int[] {4, 5}) mengirim array eksplisit, dan totalArray(new int[] {6, 7, 8}) memakai parameter array biasa. Satu perbedaan penting untuk diingat: setiap pemanggilan lepas membangun array baru, sedangkan array yang dikirim eksplisit diteruskan tanpa disalin. Mengubah isinya di dalam metode berarti mengubah array milik pemanggil, karena yang dikirim adalah referensinya.
Varargs di pustaka bawaan#
Banyak API bawaan memakai varargs, sehingga pola ini terasa pada pemakaian sehari-hari. String.format menyusun teks dari satu String pola ditambah sejumlah isian, System.out.printf menerima format dengan argumen yang jumlahnya bebas, dan List.of membungkus sejumlah elemen menjadi list. Ketiganya meletakkan parameter tetap di depan dan varargs di akhir, persis seperti bentuk sah yang dibahas di atas.
Metode main juga menerima varargs. Deklarasi public static void main(String... args) sah dan berperilaku sama dengan main(String[] args), karena di dalamnya args tetap array. Perbedaannya muncul saat metode itu dipanggil dari kode lain. Versi varargs bisa dipanggil dengan argumen terpisah, sedangkan versi array menuntut array eksplisit sebagai satu-satunya bentuk argumennya.
Kesalahan umum#
- Menaruh varargs di tengah daftar parameter atau memasang dua varargs sekaligus. Deklarasi ditolak kompilator. Pasang satu varargs di posisi terakhir.
- Mengirim
nullsebagai satu-satunya argumen. Kompilator menerimanya sebagai referensi array yangnull, lalu pembacaanlengthdi dalam metode melemparNullPointerException. Kirim array kosong sebagai gantinya. - Mendeklarasikan
proses(int[] angka)danproses(int... angka)di kelas yang sama. Keduanya memiliki signature identik setelah varargs diturunkan menjadi array, sehingga kompilasi ditolak. - Memakai varargs pada metode yang hampir selalu dipanggil dengan jumlah argumen tetap. Setiap pemanggilan lepas menyusun array baru, sehingga overload dengan jumlah parameter tetap lebih murah untuk kasus tersebut.
Ringkasan#
- Varargs ditulis dengan tiga titik setelah tipe, hanya boleh satu, dan wajib menjadi parameter terakhir.
- Di dalam metode, parameter varargs adalah array biasa yang bisa saja kosong.
- Pemanggilan lepas menyusun array baru, sedangkan pengiriman array eksplisit meneruskan referensinya tanpa salinan.
- Banyak API bawaan seperti
String.formatdanList.ofmemakai pola parameter tetap di depan ditambah varargs.
Referensi#
- Passing Information to a Method or a Constructor — Oracle — memuat bagian arbitrary number of arguments yang menjelaskan varargs.
- Formal Parameters — JLS, Java SE 21 — aturan parameter arity variabel, yaitu satu varargs yang wajib berada paling akhir.