207

I'm afraid of varargs. I don't know what to use them for.

Plus, it feels dangerous to let people pass as many arguments as they want.

What's an example of a context that would be a good place to use them?

Harry Quince
  • 2,394
  • 3
  • 15
  • 11
  • 3
    I don't see why it would be "dangerous". It's not more dangerous than having a method called a big number of times with different arguments. Do you have concerns with the stack? Then you should not, because varargs are mapped to arrays which are passed by reference. – jfpoilpret Apr 20 '09 at 04:47
  • 69
    Just wanted to chime in: there is nothing wrong with avoiding language features you aren't (yet) fully comfortable with. Far better than using features you don't understand! ;) – Steven Aug 01 '11 at 15:55
  • 2
    It is normal to fear of unknown. To learn more read about varargs here http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html . You will see, that varargs are nothing to be afraid of. Varargs are useful. Knowing how to use varargs gives you the ability to write methods like [PrintStream.format]("http://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html#printf(java.lang.String, java.lang.Object...)") :). – Developer Marius Žilėnas Nov 19 '13 at 08:08
  • 1
    This is not a criticism of varargs, but there's actually some reason to "be afraid" (until you precisely understand the limitations of varargs); this is why the @SafeVarargs annotation exists. http://stackoverflow.com/a/14252221/1593924 – Jon Coombs Jun 20 '14 at 07:45

8 Answers8

157

Varargs are useful for any method that needs to deal with an indeterminate number of objects. One good example is String.format. The format string can accept any number of parameters, so you need a mechanism to pass in any number of objects.

String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);
nbro
  • 15,395
  • 32
  • 113
  • 196
Andy White
  • 86,444
  • 48
  • 176
  • 211
  • 7
    An array parameter also can receive an indeterminate number of objects but a varargs parameter allows more flexibility and convenience at the point of invocation. You can write code to build an array and pass it, or you can let Java do it for you when you choose to receive it in a varargs parameter. – H2ONaCl Dec 24 '15 at 23:01
  • Is there some compelling reason why you wouldn't just pass a reference to some ADT, be it a simple linked list or a more full-grown List object? It could of course still be passed on the stack, just make it a struct with a size/count field in the header.. Varargs just looks like pollution that's been spread around to all languages in the C-family. – Christoffer Bubach Nov 23 '20 at 03:07
81

A good rule of thumb would be:

"Use varargs for any method (or constructor) that needs an array of T (whatever type T may be) as input".

That will make calls to these methods easier (no need to do new T[]{...}).

You could extend this rule to include methods with a List<T> argument, provided that this argument is for input only (ie, the list is not modified by the method).

Additionally, I would refrain from using f(Object... args) because its slips towards a programming way with unclear APIs.

In terms of examples, I have used it in DesignGridLayout, where I can add several JComponents in one call:

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

In the code above the add() method is defined as add(JComponent... components).

Finally, the implementation of such methods must take care of the fact that it may be called with an empty vararg! If you want to impose at least one argument, then you have to use an ugly trick such as:

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

I consider this trick ugly because the implementation of the method will be less straightforward than having just T... args in its arguments list.

Hopes this helps clarifying the point about varargs.

jfpoilpret
  • 10,449
  • 2
  • 28
  • 32
  • 1
    Did you consider adding a precondition check `if (args.length == 0) throw new RuntimeException("foo");` instead? (Since the caller was violating the contract) – Micha Wiedenmann Apr 29 '13 at 14:46
  • 25
    Well, the purpose of a good API is to prevent misuse as early as possible, so at compile time when it's possible, hence the suggestion for `void f(T arg1, T... args)` that always ensures it is never called with no argument, without need to wait until runtime. – jfpoilpret May 10 '13 at 19:52
  • I think most of the time a call to a varargs-only function with no arguments at all will just amount to also do nothing at all. Point is that providing no argument to a varargs function is most likely not going to do considerable harm. – WorldSEnder Nov 23 '16 at 12:06
  • Varargs are useful, but they aren't equivalent to using an array. Varargs are non-reifiable. So, like generics, they're affected by type erasure which could very well be an unacceptable constraint depending on the job. – Julian Feb 14 '17 at 08:32
34

I use varargs frequently for outputting to the logs for purposes of debugging.

Pretty much every class in my app has a method debugPrint():

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

Then, within methods of the class, I have calls like the following:

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

When I'm satisfied that my code is working, I comment out the code in the debugPrint() method so that the logs will not contain too much extraneous and unwanted information, but I can leave the individual calls to debugPrint() uncommented. Later, if I find a bug, I just uncomment the debugPrint() code, and all my calls to debugPrint() are reactivated.

Of course, I could just as easily eschew varargs and do the following instead:

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

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

However, in this case, when I comment out the debugPrint() code, the server still has to go through the trouble of concatenating all the variables in every call to debugPrint(), even though nothing is done with the resulting string. If I use varargs, however, the server only has to put them in an array before it realizes that it doesn't need them. Lots of time is saved.

bob
  • 341
  • 3
  • 2
13

Varargs can be used when we are unsure about the number of arguments to be passed in a method. It creates an array of parameters of unspecified length in the background and such a parameter can be treated as an array in runtime.

If we have a method which is overloaded to accept different number of parameters, then instead of overloading the method different times, we can simply use varargs concept.

Also when the parameters' type is going to vary then using "Object...test" will simplify the code a lot.

For example:

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

Here indirectly an array of int type (list) is passed as parameter and is treated as an array in the code.

For a better understanding follow this link(it helped me a lot in understanding this concept clearly): http://www.javadb.com/using-varargs-in-java

P.S: Even I was afraid of using varargs when I didn't knw abt it. But now I am used to it. As it is said: "We cling to the known, afraid of the unknown", so just use it as much as you can and you too will start liking it :)

Daniel Serodio
  • 4,229
  • 5
  • 37
  • 33
Sarvan
  • 706
  • 8
  • 16
  • 4
    C# Equivalent of varargs is "params". It also does the same thing and accepts variable number of parameters. See this for better understanding: http://www.dotnetperls.com/params – Sarvan Sep 25 '12 at 07:40
12

Varargs is the feature added in java version 1.5.

Why to use this?

  1. What if, you don't know the number of arguments to pass for a method?
  2. What if, you want to pass unlimited number of arguments to a method?

How this works?

It creates an array with the given arguments & passes the array to the method.

Example :

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

sum is 12

3

sum is 21

Arun Prakash
  • 913
  • 2
  • 8
  • 11
6

I have a varargs-related fear, too:

If the caller passes in an explicit array to the method (as opposed to multiple parameters), you will receive a shared reference to that array.

If you need to store this array internally, you might want to clone it first to avoid the caller being able to change it later.

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

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

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

While this is not really different from passing in any kind of object whose state might change later, since the array is usually (in case of a call with multiple arguments instead of an array) a fresh one created by the compiler internally that you can safely use, this is certainly unexpected behaviour.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • 1
    Correct, but this example seems a bit far-fetched. Is this likely people will use your API this way? – jfpoilpret Apr 21 '09 at 01:27
  • 2
    You never know... And especially when the number of arguments are not hard-coded on the calling side, but also collected say into a list in a loop, passing in an array is not all that uncommon. – Thilo Apr 21 '09 at 01:50
  • 5
    I think your use-case example is, generally speaking, not unlikely. One might argue that your API should not use the input array in this way, and if it does, it must document it. – Lawrence Dol Oct 14 '09 at 00:43
  • overload the method to support both; argMethod(Object.. objList) argMethod(Object[] objList) – thetoolman Nov 08 '12 at 04:19
  • 2
    @thetoolman: I don't think that is possible. It will be regarded as a duplicate method. – Thilo Nov 08 '12 at 05:49
  • "you might want to clone it first to avoid the caller being able to change it later." And ditto if the callee wants to tweak the array data, right? Far less likely, but conceivable--e.g. if it needs to preprocess the input before using it. – Jon Coombs Jun 20 '14 at 08:03
1

I use varargs frequently for constructors that can take some sort of filter object. For example, a large part of our system based on Hadoop is based on a Mapper that handles serialization and deserialization of items to JSON, and applies a number of processors that each take an item of content and either modify and return it, or return null to reject.

Kevin Peterson
  • 7,189
  • 5
  • 36
  • 43
0

In Java doc of Var-Args it is quite clear the usage of var args:

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

about usage it says:

"So when should you use varargs? As a client, you should take advantage of them whenever the API offers them. Important uses in core APIs include reflection, message formatting, and the new printf facility. As an API designer, you should use them sparingly, only when the benefit is truly compelling. Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called. "

Surendra
  • 9
  • 2