Varargs di Jawa

1. Perkenalan

Varargs diperkenalkan di Java 5 dan menyediakan metode singkat yang mendukung sejumlah parameter sembarang dari satu jenis.

Di artikel ini, kita akan melihat bagaimana kita dapat menggunakan fitur inti Java ini.

2. Sebelum Varargs

Sebelum Java 5, setiap kali kami ingin meneruskan sejumlah argumen, kami harus meneruskan semua argumen dalam array atau mengimplementasikan metode N (satu untuk setiap parameter tambahan):

public String format() { ... } public String format(String value) { ... } public String format(String val1, String val2) { ... }

3. Penggunaan Varargs

Varargs membantu kami menghindari penulisan kode boilerplate dengan memperkenalkan sintaks baru yang dapat menangani sejumlah parameter secara otomatis - menggunakan array di bawah kap.

Kita dapat mendefinisikannya menggunakan deklarasi tipe standar, diikuti dengan elipsis:

public String formatWithVarArgs(String... values) { // ... }

Dan sekarang, kita dapat memanggil metode kita dengan sejumlah argumen, seperti:

formatWithVarArgs(); formatWithVarArgs("a", "b", "c", "d");

Seperti yang disebutkan sebelumnya, vararg adalah larik jadi kita perlu bekerja dengannya seperti kita bekerja dengan larik normal.

4. Aturan

Vararg mudah digunakan. Tetapi ada beberapa aturan yang harus kami ingat:

  • Setiap metode hanya dapat memiliki satu parameter vararg
  • The varargs Argumen harus parameter terakhir

5. Polusi Timbunan

Menggunakan vararg dapat menyebabkan apa yang disebut Polusi Heap. Untuk lebih memahami polusi heap, pertimbangkan metode varargs ini :

static String firstOfFirst(List... strings) { List ints = Collections.singletonList(42); Object[] objects = strings; objects[0] = ints; // Heap pollution return strings[0].get(0); // ClassCastException }

Jika kita menyebut metode aneh ini dalam pengujian:

String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList()); assertEquals("one", one);

Kami akan mendapatkan ClassCastException meskipun kami bahkan tidak menggunakan tipe cast eksplisit apa pun di sini:

java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String

5.1. Penggunaan Aman

Setiap kali kita menggunakan varargs , compiler Java membuat sebuah array untuk menampung parameter yang diberikan. Dalam kasus ini, kompilator membuat larik dengan komponen tipe generik untuk menampung argumen.

Saat kita menggunakan vararg dengan tipe generik, karena ada potensi risiko pengecualian runtime yang fatal, compiler Java akan memperingatkan kita tentang kemungkinan penggunaan vararg yang tidak aman :

warning: [varargs] Possible heap pollution from parameterized vararg type T

Penggunaan varargs aman jika dan hanya jika:

  • Kami tidak menyimpan apa pun dalam larik yang dibuat secara implisit. Dalam contoh ini, kami menyimpan Daftar dalam larik itu
  • Kami tidak membiarkan referensi ke array yang dihasilkan lolos dari metode (lebih lanjut tentang ini nanti)

Jika kami yakin bahwa metode itu sendiri menggunakan vararg dengan aman, kami dapat menggunakan @SafeVarargs untuk menyembunyikan peringatan.

Sederhananya, penggunaan varargs aman jika kita menggunakannya untuk mentransfer sejumlah variabel argumen dari pemanggil ke metode dan tidak lebih!

5.2. Escaping varargs Referensi

Mari pertimbangkan penggunaan vararg lain yang tidak aman :

static  T[] toArray(T... arguments) { return arguments; }

Pada awalnya, tampaknya metode toArray sama sekali tidak berbahaya. Namun, karena membiarkan larik varargs lolos ke pemanggil, hal itu melanggar aturan kedua dari vararg aman .

Untuk melihat bagaimana metode ini bisa berbahaya, mari kita gunakan dengan metode lain:

static  T[] returnAsIs(T a, T b) { return toArray(a, b); }

Kemudian jika kita memanggil metode ini:

String[] args = returnAsIs("One", "Two");

Kami akan, sekali lagi, mendapatkan ClassCastException. Inilah yang terjadi ketika kita memanggil metode returnAsIs :

  • Untuk meneruskan a dan b ke metode toArray , Java perlu membuat sebuah array
  • Karena Objek [] dapat menampung item dari jenis apa pun, kompilator membuatnya
  • The toArray Metode mengembalikan diberikan Object [] ke pemanggil
  • Karena situs panggilan mengharapkan String [], kompilator mencoba mentransmisikan Objek [] ke String [] yang diharapkan , karenanya ClassCastException

Untuk pembahasan yang lebih detail tentang polusi tumpukan, sangat disarankan untuk membaca item 32 dari Java Efektif oleh Joshua Bloch.

6. Kesimpulan

Vararg dapat membuat banyak boilerplate hilang di Jawa.

Dan, berkat autoboxing implisit ke dan dari Array, mereka berperan dalam pembuktian kode kita di masa mendatang.

Seperti biasa, semua contoh kode dari artikel ini dapat tersedia di repositori GitHub kami.