7

In the long debate of using arrays vs lists in the public API of Java classes, I tend to prefer lists in most situations. However, I also found convenient to use var arguments in many constructors and methods, which require declaring an argument of the method (the last one) as an array (implicitly adding "..." before the parameter name).

Since in many of these methods I do want to provide a programmer the possibility to either explicitly list the arguments (with var args) or use a pre-defined collection when invoking the method, I often end up defining a constructor or method with var arguments, and an overloaded version that accepts a list instead of the var args array. For example:

public void myMethod(X ...items) {  
    myMethod(Arrays.asList(items));
}  

private void myMethod(List<X> items) {  
    ...  
}  

I know that in theory I do not need to overload the method replacing the var args array with a list if I want the programmer to send a collection of objects. He could just send an array.

The reason I often do this is because most (if not all) of the methods in my API use lists instead of arrays, and it is a bit weird that for one or two methods requirying collection of objects, the programmer needs to work with arrays (in cases when the var args are not convenient). So I provide an overloaded version working with list for consistency.

However, since this is a recurrent problem, I have the uncomfortable feeling of being writing boilerplate code too often. I would like to receive feedback if my motivation of keeping my interface consistent (accepting var arrays or lists, but not forcing the programmer to work with arrays if not really required) is valid enough to keep writing overloaded versions using lists for most of my methods requirying var arguments.

I would like to highlight that I know that for certain methods arrays could be more convenient than lists. My question concerns situations where the only motivation for declaring the last argument of the method as an array is because in certain scenarios using var arguments can be convinient.

UPDATE

Thanks for your feedback. My conclusions at the moment are the following:

  • Reduce the usage of var args as much as possible.
  • Continue adding an overloaded version of the method with var args, such as the array argument is replaced by a list (or an Iterable, as @Kevin pointed out), in cases where it can be useful to have the choice to invoke the method with either var args or with a collection.
  • Stop using Java as soon as possible :) (I already knew that one)
1
  • 3
    Do NOT require List<X> unless you need random access. That will be very inconvenient for future programmers who have a Set or a Map or another type of collection, and want to call your API. Instead declare the argument type to be Iterable<X>. Commented Feb 11, 2013 at 17:19

3 Answers 3

5

You're overthinking the problem. You want to use a list (array or some other iterable) for your arguments when it's likely the consumer of your function would already have things in a list. You want to use variable arguments when you might want to call a function with a different number of arguments.

A classic example of when you should use varargs is C's printf(). Using varargs makes sense here because, in the general case, there's no reason to put a bunch of arbitrary values in a list just to print something. A good example of where you'd probably want a list is a sum() where you're probably operating on a bunch of related values that would likely be stashed away together.

It's not something you need to be dogmatic about or have rules for. Use some common sense and write code that people can follow & doesn't force you to jump through arbitrary hoops.

-2

The only justification for a client wanting a varargs that I can think of is simply a style argument where it doesn't "feel" right for a client to group things together in a collection on their side.

An example might be when your client has several DAOs which implement a common interface but talk to logically distinct data sources, like a Customer table and an Address table. Although a client app might use a common interface to access this data, the query terms they use probably won't be the same for both (you might query Customers by last name but you wouldn't query Addresses that way). Since a client typically wouldn't have a use case to iterate over a List of that interface, they probably won't have naturally stashed those two DAOs in a list.

However, lists are a more useful data structure to work with than arrays. Dynamic memory allocation, .sublist(x,y), .clear(), iterators, etc are all handy to have which is probably why you are already in the habit of using lists on the backend. So why not expect the client calling your API feel the same way? Arrays.asList(item1, item2) is easy for a client to use, so I do not see a reason to provide the varargs API. Only provide the List API.

In addition, I don't agree with Kevin's comment that you should specify the Iterable interface in your API. You lose all of the useful APIs in the List interface just to save your client who has a set from calling "new ArrayList(set)" and passing that to your API. At a minimum your API should take a Collection.

3
  • 1
    Hi @Seth, not sure if I got your last paragraph. There you said that you also believe lists are better in most situations, but then you said it is a pain for the clients to use Arrays.asList(item1,item2) and recommend me to suppress the redundant API (the one with lists ?). So according to that I should leave only the method with arrays despite the fact the rest of the methods in the class work with lists ?
    – Sergio
    Commented Feb 11, 2013 at 11:06
  • @Sergio: He said it was easy to use Arrays.asList, so it wouldn't be that much trouble for a user to build a List out of their objects. I believe Seth is saying that you should not write methods that take an array or varargs - make them take a List, and if the user doesn't have things in a List already, it's no trouble to call Arrays.asList.
    – Nate W.
    Commented Mar 14, 2013 at 19:03
  • hi @Shakedown, my comment was related to the first version of the answer, (you can see the edits I think). I will delete it since it does not make sense in the last version I think.
    – Sergio
    Commented Mar 14, 2013 at 21:02
-6

Varargs is a bad idea in modern languages. It was a simplifying assumption in C, but should never have made the jump to Java or C# (C++ can be forgiven because it really wanted to be a superset of C). Any language that has a first-class List, even before generics and List<Object>, should be able to represent any varargs function much better with a list parameter. And if you eliminate varargs completely, a lot of method signatures that are ambiguous with varargs cease to be without.

3
  • 4
    With varargs, I don't have to explicitly assemble a collection if I already have the items. Even with the most convenient syntax available in C# right now, it's Foo(new List<SomeHugeType> {param1, param2}) versus Foo(param1, param2). And ambiguity of calls is more effectively battled by restricting overloading in general ;-)
    – user7043
    Commented Feb 10, 2013 at 23:31
  • 4
    I thought like you before ("it's-all-a-useless-syntactic-sugar blah blah"), but after having recently reviewed diffs of about 200 files migrated from Java 4 (no varargs) to more modern version (with varargs), I don't think so anymore
    – gnat
    Commented Feb 11, 2013 at 12:34
  • 3
    -1: Maybe true, but Java isn't a modern language. Modern languages have convenient syntax for List and Map literals. Java does not, so using varargs is often the most convenient. Commented Feb 11, 2013 at 17:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.