Kapan Anda menggunakan vararg di Jawa?

192

Saya takut varargs. Saya tidak tahu untuk apa menggunakannya.

Ditambah lagi, rasanya berbahaya membiarkan orang mengeluarkan argumen sebanyak yang mereka inginkan.

Apa contoh konteks yang akan menjadi tempat yang baik untuk menggunakannya?

Harry Quince
sumber
3
Saya tidak mengerti mengapa itu akan "berbahaya". Itu tidak lebih berbahaya daripada memiliki metode yang disebut sejumlah besar kali dengan argumen yang berbeda. Apakah Anda memiliki masalah dengan stack? Maka Anda tidak boleh, karena vararg dipetakan ke array yang dilewatkan oleh referensi.
jfpoilpret
66
Hanya ingin berpadu: tidak ada yang salah dengan menghindari fitur bahasa yang Anda (belum) merasa nyaman sepenuhnya. Jauh lebih baik daripada menggunakan fitur yang tidak Anda mengerti! ;)
Steven
2
Adalah normal untuk takut akan hal yang tidak diketahui. Untuk mempelajari lebih lanjut, baca tentang varargs di sini docs.oracle.com/javase/tutorial/java/javaOO/arguments.html . Anda akan melihat, bahwa vararg tidak perlu ditakuti. Varargs bermanfaat. Mengetahui cara menggunakan varargs memberi Anda kemampuan untuk menulis metode seperti [PrintStream.format] (" docs.oracle.com/javase/7/docs/api/java/io/… , java.lang.Object ...)" ) :).
Pengembang Marius Žilėnas
1
Ini bukan kritik terhadap vararg, tetapi sebenarnya ada beberapa alasan untuk "takut" (sampai Anda benar-benar memahami keterbatasan vararg); inilah mengapa penjelasan @SafeVarargs ada. stackoverflow.com/a/14252221/1593924
Jon Coombs

Jawaban:

150

Varargs yang berguna untuk metode apapun bahwa kebutuhan untuk berurusan dengan jumlah tak tentu dari benda-benda . Salah satu contoh yang bagus adalah String.format. String format dapat menerima sejumlah parameter, jadi Anda memerlukan mekanisme untuk meneruskan sejumlah objek.

String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);
Andy White
sumber
5
Parameter array juga dapat menerima jumlah objek yang tidak ditentukan tetapi parameter varargs memungkinkan lebih banyak fleksibilitas dan kenyamanan pada titik doa. Anda dapat menulis kode untuk membangun array dan meneruskannya, atau Anda dapat membiarkan Java melakukannya untuk Anda ketika Anda memilih untuk menerimanya dalam parameter varargs.
H2ONaCl
79

Aturan praktis yang baik adalah:

+ Msgstr "Gunakan vararg untuk metode apa pun (atau konstruktor) yang membutuhkan larik T (apa pun tipe T) sebagai masukan".

Itu akan membuat panggilan ke metode ini lebih mudah (tidak perlu dilakukan new T[]{...}).

Anda bisa memperluas aturan ini untuk memasukkan metode dengan List<T>argumen, asalkan argumen ini hanya untuk input (yaitu, daftar tidak dimodifikasi oleh metode).

Selain itu, saya akan menahan diri untuk tidak menggunakan f(Object... args)karena tergelincir ke arah cara pemrograman dengan API tidak jelas.

Dalam hal contoh, saya telah menggunakannya di DesignGridLayout , di mana saya dapat menambahkan beberapa JComponentdalam satu panggilan:

layout.row().grid(new JLabel("Label")).add(field1, field2, field3);

Dalam kode di atas metode add () didefinisikan sebagai add(JComponent... components).

Akhirnya, implementasi metode semacam itu harus memperhatikan fakta bahwa itu dapat disebut dengan vararg kosong! Jika Anda ingin memaksakan setidaknya satu argumen, maka Anda harus menggunakan trik jelek seperti:

void f(T arg1, T... args) {...}

Saya menganggap trik ini jelek karena penerapan metode ini akan lebih mudah daripada hanya T... argsdalam daftar argumennya.

Berharap ini membantu memperjelas poin tentang varargs.

jfpoilpret
sumber
1
Apakah Anda mempertimbangkan untuk menambahkan pemeriksaan prasyarat if (args.length == 0) throw new RuntimeException("foo");? (Karena penelepon melanggar kontrak)
Micha Wiedenmann
24
Nah, tujuan dari API yang baik adalah untuk mencegah penyalahgunaan sedini mungkin, jadi pada waktu kompilasi ketika memungkinkan, maka saran untuk void f(T arg1, T... args)itu selalu memastikan tidak pernah dipanggil tanpa argumen, tanpa perlu menunggu sampai runtime.
jfpoilpret
Saya pikir sebagian besar waktu panggilan ke fungsi hanya-varargs tanpa argumen sama sekali hanya akan berarti tidak melakukan apa-apa sama sekali. Intinya adalah bahwa tidak memberikan argumen ke fungsi varargs kemungkinan besar tidak akan merugikan.
WorldSEnder
Varargs berguna, tetapi mereka tidak setara dengan menggunakan array. Vararg tidak dapat diverifikasi. Jadi, seperti halnya obat generik, mereka dipengaruhi oleh penghapusan tipe yang bisa menjadi kendala yang tidak dapat diterima tergantung pada pekerjaan.
Julian
34

Saya sering menggunakan varargs untuk menghasilkan log untuk keperluan debugging.

Hampir setiap kelas di aplikasi saya memiliki metode debugPrint ():

private void debugPrint(Object... msg) {
    for (Object item : msg) System.out.print(item);
    System.out.println();
}

Kemudian, dalam metode kelas, saya memiliki panggilan seperti berikut:

debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
    serialNo, ", the grade is ", grade);

Ketika saya puas bahwa kode saya berfungsi, saya mengomentari kode dalam metode debugPrint () sehingga log tidak akan berisi terlalu banyak informasi yang tidak diinginkan dan tidak diinginkan, tetapi saya dapat meninggalkan panggilan individu ke debugPrint () tanpa komentar. Kemudian, jika saya menemukan bug, saya hanya menghilangkan tanda komentar pada kode debugPrint (), dan semua panggilan saya ke debugPrint () diaktifkan kembali.

Tentu saja, saya bisa dengan mudah menghindari varargs dan melakukan yang berikut:

private void debugPrint(String msg) {
    System.out.println(msg);
}

debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
    + serialNo + ", the grade is " + grade);

Namun, dalam kasus ini, ketika saya mengomentari kode debugPrint (), server masih harus melalui masalah menggabungkan semua variabel dalam setiap panggilan ke debugPrint (), meskipun tidak ada yang dilakukan dengan string yang dihasilkan. Namun, jika saya menggunakan varargs, server hanya perlu meletakkannya dalam array sebelum menyadari bahwa itu tidak membutuhkannya. Banyak waktu yang dihemat.

bob
sumber
4
Anda dapat menerapkan metode debug di superclass untuk mencetak objek apa pun menggunakan refleksi.
Lluis Martinez
12

Varargs dapat digunakan ketika kita tidak yakin tentang jumlah argumen yang harus disampaikan dalam suatu metode. Ini menciptakan array parameter dengan panjang yang tidak ditentukan di latar belakang dan parameter tersebut dapat diperlakukan sebagai array dalam runtime.

Jika kita memiliki metode yang kelebihan beban untuk menerima jumlah parameter yang berbeda, maka alih-alih menggunakan kelebihan waktu yang berbeda, kita cukup menggunakan konsep varargs.

Juga ketika tipe parameter akan bervariasi kemudian menggunakan "Object ... test" akan menyederhanakan banyak kode.

Sebagai contoh:

public int calculate(int...list) {
    int sum = 0;
    for (int item : list) {
        sum += item;
    }
    return sum;
}

Di sini secara tidak langsung array tipe int (daftar) dilewatkan sebagai parameter dan diperlakukan sebagai array dalam kode.

Untuk pemahaman yang lebih baik ikuti tautan ini (ini banyak membantu saya dalam memahami konsep ini dengan jelas): http://www.javadb.com/using-varargs-in-java

PS: Bahkan saya takut menggunakan vararg ketika saya tidak tahu itu. Tapi sekarang saya sudah terbiasa. Seperti dikatakan: "Kami berpegang teguh pada yang dikenal, takut pada yang tidak diketahui", jadi gunakan saja sebanyak yang Anda bisa dan Anda juga akan mulai menyukainya :)

Sarvan
sumber
4
C # Setara dengan varargs adalah "params". Itu juga melakukan hal yang sama dan menerima jumlah parameter variabel. Lihat ini untuk pemahaman yang lebih baik: dotnetperls.com/params
Sarvan
11

Varargs adalah fitur yang ditambahkan dalam java versi 1.5.

Mengapa menggunakan ini?

  1. Bagaimana jika, Anda tidak tahu jumlah argumen yang harus dilewati untuk suatu metode?
  2. Bagaimana jika, Anda ingin memberikan argumen tanpa batas ke suatu metode?

Bagaimana ini bekerja?

Itu menciptakan array dengan argumen yang diberikan & melewati array ke metode.

Contoh:

public class Solution {



    public static void main(String[] args) {
        add(5,7);
        add(5,7,9);
    }

    public static void add(int... s){
        System.out.println(s.length);
        int sum=0;
        for(int num:s)
            sum=sum+num;
        System.out.println("sum is "+sum );
    }

}

Output:

2

jumlahnya 12

3

jumlah adalah 21

Arun Prakash
sumber
6

Saya memiliki ketakutan terkait varargs juga:

Jika pemanggil lewat dalam array eksplisit ke metode (yang bertentangan dengan beberapa parameter), Anda akan menerima referensi bersama untuk array itu.

Jika Anda perlu menyimpan array ini secara internal, Anda mungkin ingin mengkloningnya terlebih dahulu untuk menghindari penelepon yang dapat mengubahnya nanti.

 Object[] args = new Object[] { 1, 2, 3} ;

 varArgMethod(args);  // not varArgMethod(1,2,3);

 args[2] = "something else";  // this could have unexpected side-effects

Meskipun ini tidak benar-benar berbeda dari meneruskan objek apa pun yang keadaannya mungkin berubah kemudian, karena array biasanya (dalam kasus panggilan dengan beberapa argumen, bukan array) yang baru dibuat oleh kompiler secara internal yang Anda dapat dengan aman gunakan, ini tentu perilaku yang tidak terduga.

Thilo
sumber
1
Benar, tetapi contoh ini tampaknya agak dibuat-buat. Apakah ini kemungkinan orang akan menggunakan API Anda dengan cara ini?
jfpoilpret
2
Anda tidak pernah tahu ... Dan terutama ketika jumlah argumen tidak sulit dikodekan pada sisi panggilan, tetapi juga dikumpulkan mengatakan ke dalam daftar dalam satu lingkaran, melewati dalam array tidak semua yang tidak biasa.
Thilo
5
Saya pikir contoh kasus penggunaan Anda, secara umum, bukan tidak mungkin. Orang mungkin berpendapat bahwa API Anda seharusnya tidak menggunakan array input dengan cara ini, dan jika ya, itu harus mendokumentasikannya.
Lawrence Dol
membebani metode untuk mendukung keduanya; argMethod (Object .. objList) argMethod (Object [] objList)
thetoolman
2
@thoolool: Saya rasa itu tidak mungkin. Ini akan dianggap sebagai metode duplikat.
Thilo
1

Saya sering menggunakan varargs untuk konstruktor yang dapat mengambil semacam objek filter. Misalnya, sebagian besar sistem kami berdasarkan Hadoop didasarkan pada seorang Mapper yang menangani serialisasi dan deserialisasi item ke JSON, dan menerapkan sejumlah prosesor yang masing-masing mengambil item konten dan memodifikasi dan mengembalikannya, atau mengembalikan null menolak.

Kevin Peterson
sumber
1

Dalam Java doc of Var-Args cukup jelas penggunaan var args:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html

tentang penggunaannya dikatakan:

"Jadi kapan Anda harus menggunakan varargs? Sebagai klien, Anda harus memanfaatkannya kapan pun API menawarkannya. Penggunaan penting dalam API inti mencakup refleksi, pemformatan pesan, dan fasilitas printf baru. Sebagai perancang API, Anda harus menggunakannya hemat, hanya ketika manfaatnya benar-benar menarik. Secara umum, Anda tidak boleh kelebihan metode varargs, atau akan sulit bagi programmer untuk mencari tahu mana kelebihan beban dipanggil. "

Surendra
sumber