Java'da varargs ne zaman kullanılır?


192

Korkarım varargs. Onları ne için kullanacağımı bilmiyorum.

Ayrıca, insanların istedikleri kadar argüman geçirmelerine izin vermek tehlikeli hissettiriyor.

Bunları kullanmak için iyi bir yer olabilecek bir bağlam örneği nedir?


3
Neden "tehlikeli" olacağını anlamıyorum. Farklı argümanlarla çok kez denilen bir yönteme sahip olmaktan daha tehlikeli değildir. Yığınla ilgili endişeleriniz var mı? O zaman yapmamalısınız, çünkü varargs referans olarak geçirilen dizilere eşlenir.
jfpoilpret

66
Sadece seslenmek istedim: (henüz) tam olarak rahat olmadığınız dil özelliklerinden kaçınmanın yanlış bir yanı yok. Anlamadığınız özellikleri kullanmaktan çok daha iyi! ;)
Steven

2
Bilinmeyenden korkmak normaldir. Daha fazla bilgi edinmek için burada docs.oracle.com/javase/tutorial/java/javaOO/arguments.html adresini ziyaret edin . Göreceksiniz, varargs korkacak bir şey değildir. Varargs kullanışlıdır. Varargs'ın nasıl kullanılacağını bilmek size [PrintStream.format] (" docs.oracle.com/javase/7/docs/api/java/io/… , java.lang.Object ...)" gibi yöntemler yazma yeteneği verir. ) :).
Geliştirici Marius Žilėnas

1
Bu bir varargs eleştirisi değildir, ama aslında "korkmak" için bir neden vardır (varargs'ın sınırlamalarını tam olarak anlayana kadar); @SafeVarargs ek açıklaması bu yüzden vardır. stackoverflow.com/a/14252221/1593924
Jon Coombs

Yanıtlar:


150

Varargs , belirsiz sayıda nesne ile ilgilenmesi gereken herhangi bir yöntem için kullanışlıdır . Bunun iyi bir örneği . Biçim dizesi herhangi bir sayıda parametreyi kabul edebilir, bu nedenle istediğiniz sayıda nesneyi iletmek için bir mekanizmaya ihtiyacınız vardır.String.format

String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);

5
Bir dizi parametresi ayrıca belirsiz sayıda nesne alabilir, ancak varargs parametresi çağırma noktasında daha fazla esneklik ve kolaylık sağlar. Bir dizi oluşturmak ve geçmek için kod yazabilir veya varargs parametresinde almayı seçtiğinizde Java'nın sizin için yapmasına izin verebilirsiniz.
H2ONaCl

79

İyi bir kural şöyle olacaktır:

Msgstr "Girdi olarak T dizisine ihtiyaç duyan herhangi bir yöntem (veya yapıcı) için varargs kullanın".

Bu, bu yöntemlere çağrı yapmayı kolaylaştıracaktır (yapmaya gerek yoktur new T[]{...}).

List<T>Bu bağımsız değişkeni yalnızca girdi için olması koşuluyla, bağımsız değişkeni içeren yöntemleri içerecek şekilde genişletebilirsiniz (yani, liste yöntem tarafından değiştirilmemiştir).

Ayrıca, f(Object... args)belirsiz API'lerle bir programlama yoluna kaydığı için kullanmaktan kaçınırım .

Örnekler açısından, ben bir çağrıda birkaç s ekleyebilirsiniz DesignGridLayout , kullandım JComponent:

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

Yukarıdaki kodda add () yöntemi olarak tanımlanır add(JComponent... components).

Son olarak, bu tür yöntemlerin uygulanması, boş bir vararg ile çağrılabileceği gerçeğine dikkat etmelidir! En az bir argüman uygulamak istiyorsanız, o zaman çirkin bir numara kullanmalısınız:

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

Bu hileyi çirkin görüyorum çünkü yöntemin uygulanması sadece T... argsargümanlar listesinde olmaktan daha az basit olacaktır .

Bu varargs ile ilgili noktayı açıklığa kavuşturmayı umuyor.


1
if (args.length == 0) throw new RuntimeException("foo");Bunun yerine bir ön koşul kontrolü eklemeyi düşündünüz mü ? (Arayan kişi sözleşmeyi ihlal ettiği için)
Micha Wiedenmann

24
İyi bir API'nin amacı, kötüye kullanımı mümkün olduğunca erken önlemektir, bu nedenle mümkün olduğunda derleme zamanında, bu nedenle öneri void f(T arg1, T... args), çalışma zamanına kadar beklemeye gerek kalmadan, hiçbir zaman argüman olmadan çağrılmamasını sağlar.
jfpoilpret

Bence çoğu zaman sadece varargs-fonksiyonuna hiçbir argüman olmadan çağrı da hiçbir şey yapmaz. Burada önemli olan nokta, bir varargs fonksiyonuna hiçbir argüman sunmanın büyük olasılıkla önemli bir zarar vermeyeceğidir.
WorldSEnder

Varargs yararlıdır, ancak bir dizi kullanmaya eşdeğer değildir. Varargs yeniden kullanılamaz. Yani, jenerikler gibi, işe bağlı olarak kabul edilemez bir kısıtlama olabilen tip silinmesinden etkilenirler.
Julian

34

Hata ayıklama amacıyla günlüklere çıkış için varargs kullanıyorum.

Uygulamamdaki hemen hemen her sınıfın bir debugPrint () yöntemi var:

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

Sonra, sınıfın yöntemleri içinde, aşağıdaki gibi çağrıları var:

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

Kodumun çalıştığından memnun olduğumda, günlüklerin çok fazla gereksiz ve istenmeyen bilgi içermemesi için debugPrint () yöntemindeki kodu yorumluyorum, ancak debugPrint () 'e tek tek çağrıları uncommented bırakabilirsiniz. Daha sonra, bir hata bulursam, ben sadece debugPrint () kodunu uncomment ve debugPrint () tüm çağrıları yeniden etkinleştirilir.

Tabii ki, varargs kadar kolay eschew olabilir ve bunun yerine aşağıdakileri yapabilirim:

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

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

Ancak, bu durumda, debugPrint () kodunu yorumladığımda, sonuç dizesiyle hiçbir şey yapılmamasına rağmen, sunucunun debugPrint () öğesine yapılan her çağrıdaki tüm değişkenleri birleştirme sorununu yaşaması gerekir. Ancak, varargs kullanırsanız, sunucu sadece onlara ihtiyaç olmadığını fark önce bir diziye koymak zorunda. Çok zaman kazandırır.


4
Yansıma kullanarak herhangi bir nesneyi yazdırmak için üst sınıfta bir hata ayıklama yöntemi uygulayabilirsiniz.
Lluis Martinez

12

Varargs, bir yöntemde iletilecek argüman sayısından emin olmadığımızda kullanılabilir. Arka planda belirtilmemiş uzunlukta bir parametre dizisi oluşturur ve böyle bir parametre çalışma zamanında dizi olarak ele alınabilir.

Farklı sayıda parametreyi kabul etmek için aşırı yüklenmiş bir yöntemimiz varsa, yöntemi farklı zamanlarda aşırı yüklemek yerine, varargs konseptini kullanabiliriz.

Ayrıca parametrelerin tipi değiştiğinde "Object ... test" kullanılması kodu çok basitleştirecektir.

Örneğin:

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

Burada dolaylı olarak int tipi (list) bir dizi parametre olarak geçirilir ve kodda bir dizi olarak ele alınır.

Daha iyi bir anlayış için bu bağlantıyı takip edin (bu kavramı açıkça anlamamda bana çok yardımcı oldu): http://www.javadb.com/using-varargs-in-java

Not: Ben bile bilmiyordum varargs kullanmak korkuyordu. Ama şimdi alışkınım. Söylendiği gibi: "Bilinmeyene korkan, bilinene sarılıyoruz", bu yüzden mümkün olduğunca çok kullanın ve siz de beğenmeye başlayacaksınız :)


4
C # Varargs eşdeğeri "params" dir. Aynı şeyi yapar ve değişken sayıda parametreyi kabul eder. Daha iyi anlamak için buna bakın: dotnetperls.com/params
Sarvan

11

Varargs, java sürüm 1.5'te eklenen özelliktir.

Bunu neden kullanmalıyım?

  1. Bir yöntem için iletilecek bağımsız değişken sayısını bilmiyorsanız ne olur?
  2. Ya bir yönteme sınırsız sayıda argüman iletmek isterseniz?

Bu nasıl çalışır?

Verilen bağımsız değişkenlerle bir dizi oluşturur ve diziyi yönteme iletir.

Misal :

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 );
    }

}

Çıktı :

2

toplam 12

3

toplam 21


6

Ben de varargs ile ilgili bir korkum var:

Arayan, yönteme açık bir dizi geçirirse (birden çok parametrenin aksine), bu diziye paylaşılan bir başvuru alırsınız.

Bu diziyi dahili olarak depolamanız gerekiyorsa, arayanın daha sonra değiştirebilmesini önlemek için önce diziyi kopyalamak isteyebilirsiniz.

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

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

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

Bu durum, durumu daha sonra değişebilecek herhangi bir nesne türünden geçmekten gerçekten farklı olmasa da, dizi genellikle (bir dizi yerine birden çok bağımsız değişkeni olan bir çağrı durumunda) derleyici tarafından dahili olarak oluşturulan ve güvenli bir şekilde oluşturabileceğiniz yeni bir nesne kullanın, bu kesinlikle beklenmedik bir davranış.


1
Doğru, ancak bu örnek biraz uzak görünüyor. Bu kişilerin API'nızı bu şekilde kullanması olası mı?
jfpoilpret

2
Asla bilemezsiniz ... Ve özellikle de argümanların sayısı çağıran tarafta sabit olarak kodlanmadığında, aynı zamanda bir döngü içinde bir listeye toplandığında, bir diziye geçmek o kadar da nadir değildir.
Thilo

5
Bence kullanım örneği, genel olarak konuşursak, pek olası değildir. API'nızın giriş dizisini bu şekilde kullanmaması gerektiği iddia edilebilir ve eğer varsa, bunu belgelemesi gerekir.
Lawrence Dol

her ikisini de desteklemek için aşırı yükleme yöntemi; argMethod (Object .. objList) argMethod (Object [] objList)
thetoolman

2
@thetoolman: Bunun mümkün olduğunu düşünmüyorum. Yinelenen bir yöntem olarak kabul edilecektir.
Thilo

1

Bir tür filtre nesnesi alabilen kurucular için varargs sık kullanıyorum. Örneğin, Hadoop tabanlı sistemimizin büyük bir kısmı, JSON'a öğelerin serileştirilmesini ve serileştirilmesini işleyen ve her birinin bir içerik öğesi alıp değiştiren veya döndüren veya null döndüren bir dizi işlemciyi uygulayan bir Eşleyici'ye dayanır. reddetmek.


1

Var-Args'ın Java belgesinde var arglerin kullanımı oldukça açıktır:

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

kullanım hakkında diyor:

"Peki ne zaman varargs kullanmalısınız? Bir istemci olarak, API her sunduğunda bunlardan yararlanmalısınız. Temel API'lardaki önemli kullanımlar yansıma, mesaj biçimlendirme ve yeni printf özelliğini içerir. Bir API tasarımcısı olarak bunları kullanmalısınız Genel olarak konuşursak, bir varargs yöntemini aşırı yüklememelisiniz, yoksa programcıların hangi aşırı yüklemenin çağrıldığını anlaması zor olacaktır. "

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.