Conclusion will be drawn at the end. Skip to the end if you just want the conclusion.
The primary goal is performance.
If there are lots of use cases where there is only 1 or 2 elements that would get passed, you can avoid the creation of an array. Yes, there is still a zero-length array that will be passed, but since a zero-length array cannot be modified, the JVM is allowed to pass a shared instance for example which if cached has no performance impact at all.
The most shining example for this is the EnumSet.of()
methods (which returns an EnumSet
of the listed enum instances).
You'll see the following overloads:
static <E extends Enum<E>> EnumSet<E> of(E e);
static <E extends Enum<E>> EnumSet<E> of(E first, E... rest);
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2);
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3);
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4);
static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5);
If you call the of()
method with 5 or less elements, there will be no array created because there are overloads that can take 5 or less elements. Performance is also mentioned in the javadoc of EnumSet.of(E first, E... rest)
This factory, whose parameter list uses the varargs feature, may be
used to create an enum set initially containing an arbitrary number of
elements, but it is likely to run slower than the overloadings that do
not use varargs.
As to why to use of(E first, E... rest)
even if there is a separate of(E e1, E e2)
:
This is simply a convenience for the implementation. If you declare a first
parameter, you can use it without having to check the array's length or having to use indexing. You can use to check its type for example (which is often important when working with generics).
It doesn't really force to pass at least one argument because you can just as easily pass a null
as you could pass an empty array if there would only be the vararg parameter.
Vararg vs array
If the type of the array is not a primitive type then there is no real difference, except the array parameter forces you to explicitly create the array while the vararg parameter allows you to either pass an array or just list the elements.
Despite the historical reasons for array parameter (varargs only joined Java with 5.0) there are still places when arrays have to be used:
- If the array parameter is an "outgoing" parameter meaning the method receiving the array whishes to fill the array. Example: InputStream.read(byte[] b)
- If there are other parameters, possibly multiple arrays, obviously vararg is not enough as there can be only one vararg parameter (which also must be at the end).
Iterable parameter
Iterable
in this case is an alternative to pass multiple values to the method but it is not a replacement for array and vararg parameters. Iterable
is for collections, as arrays or listing the elements cannot be used if the parameter is Iterable
(arrays don't implement Iterable
). If the caller has the input data in the form of a collection (e.g. List
or Set
), the Iterable
parameter is the most convenient, the most general and the most efficient way to pass the elements.
Drawing a conclusion
Back to your original Scenario A and B. Since both of your scenarios contain the method with the Iterable
parameter and since Iterable
s do not "mix" with arrays, I reduce the question by omitting those:
Scenario A: (one method)
void add(T... valueArr)
Scenario B: (two methods)
void add(T value, T... moreValueArr)
void add(T[] valueArr)
Since the method add()
only reads from the array (and not writes to it; assumed from the name add
), every use case can be solved with both of them. I would go with Scenario A for simplicity.