Varargs di Jawa

1. Pengenalan

Varargs diperkenalkan di Java 5 dan memberikan cara singkat untuk kaedah yang menyokong sebilangan parameter satu jenis.

Dalam artikel ini, kita akan melihat bagaimana kita dapat menggunakan ciri inti Java ini.

2. Sebelum Varargs

Sebelum Java 5, setiap kali kami ingin menyampaikan sejumlah argumen sewenang-wenangnya, kami harus meneruskan semua argumen dalam array atau menerapkan kaedah 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 kita mengelakkan penulisan kod pelat boiler dengan memperkenalkan sintaks baru yang dapat menangani bilangan parameter sewenang-wenang secara automatik - menggunakan susunan di bawah tenda.

Kita dapat menentukannya menggunakan deklarasi jenis standard, diikuti dengan elipsis:

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

Dan sekarang, kita boleh memanggil kaedah kita dengan sejumlah argumen sewenang-wenangnya, seperti:

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

Seperti yang telah disebutkan sebelumnya, varargs adalah tatasusunan, jadi kita perlu bekerjasama dengan mereka sama seperti kita bekerja dengan susunan biasa.

4. Peraturan

Varargs mudah digunakan. Tetapi ada beberapa peraturan yang harus kita ingat:

  • Setiap kaedah hanya boleh mempunyai satu parameter varargs
  • The varargs hujah perlu menjadi parameter yang lalu

5. Pencemaran Tumpukan

Menggunakan varargs boleh menyebabkan Pencemaran Tumpukan. Untuk lebih memahami pencemaran timbunan, pertimbangkan kaedah 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 }

Sekiranya kita menyebut kaedah pelik ini dalam ujian:

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

Kami akan mendapat ClassCastException walaupun kami tidak menggunakan pelakon jenis eksplisit di sini:

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

5.1. Penggunaan Selamat

Setiap kali kita menggunakan varargs , penyusun Java membuat array untuk menahan parameter yang diberikan. Dalam kes ini, penyusun membuat susunan dengan komponen jenis generik untuk menahan argumen.

Apabila kita menggunakan vararg dengan jenis generik, kerana ada kemungkinan risiko pengecualian runtime yang fatal, penyusun Java memberi amaran kepada kita tentang kemungkinan penggunaan varargs yang tidak selamat :

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

Penggunaan varargs selamat jika dan hanya jika:

  • Kami tidak menyimpan apa-apa dalam susunan yang dibuat secara tersirat. Dalam contoh ini, kami menyimpan Senarai dalam tatasusunan itu
  • Kami tidak membiarkan rujukan ke array yang dihasilkan melarikan diri dari kaedah (lebih lanjut mengenai ini kemudian)

Sekiranya kita yakin bahawa kaedah itu sendiri menggunakan vararg dengan selamat, kita boleh menggunakan @SafeVarargs untuk menekan amaran.

Secara ringkasnya, yang varargs penggunaan adalah selamat jika kita menggunakannya untuk memindahkan beberapa pembolehubah hujah daripada pemanggil kepada kaedah dan apa-apa lagi!

5.2. Melarikan Rujukan Varargs

Mari pertimbangkan penggunaan vararg lain yang tidak selamat :

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

Pada mulanya, nampaknya kaedah toArray sama sekali tidak berbahaya. Namun, kerana membiarkan array varargs melarikan diri ke pemanggil, ia melanggar peraturan kedua varargs yang selamat .

Untuk melihat bagaimana kaedah ini berbahaya, mari kita gunakan kaedah lain:

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

Kemudian jika kita memanggil kaedah ini:

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

Kami sekali lagi akan mendapat ClassCastException. Inilah yang berlaku apabila kita memanggil kaedah returnAsIs :

  • Untuk meneruskan a dan b ke kaedah toArray , Java perlu membuat array
  • Oleh kerana Objek [] dapat menyimpan item dari jenis apa pun, penyusun membuatnya
  • The toArray Cara mengembalikan diberikan Objek [] kepada pemanggil
  • Oleh kerana laman panggilan menjangkakan String [], penyusun cuba menghantar Objek [] ke String yang diharapkan [] , maka ClassCastException

Untuk perbincangan yang lebih terperinci mengenai pencemaran timbunan, sangat disarankan untuk membaca item 32 Java Effective oleh Joshua Bloch.

6. Kesimpulannya

Varargs dapat membuat banyak boilerplate hilang di Jawa.

Dan, berkat autoboxing tersirat mereka ke dan dari Array, mereka berperanan dalam membuktikan kod kami di masa hadapan.

Seperti biasa, semua contoh kod dari artikel ini boleh didapati di repositori GitHub kami.