46

Varargs:

public static void foo(String... string_array) { ... }

versus

Single array param:

public static void bar(String[] string_array) { ... }

Java 1.6 seems to accept/reject the following:

String[] arr = {"abc", "def", "ghi"};
foo(arr);  // accept
bar(arr);  // accept
foo("abc", "def", "ghi");  // accept
bar("abc", "def", "ghi");  // reject

Assuming the above is true/correct, why not always use varargs instead of single array param? Seems to add a touch of caller flexiblity for free.

Can an expert share the internal JVM difference, if there is one?

Thanks.

Void Star
  • 2,401
  • 4
  • 32
  • 57
kevinarpe
  • 20,319
  • 26
  • 127
  • 154

6 Answers6

44

Arrays have been around from the beginning of Java, while varargs are a fairly recent addition. Thus a lot of older code still happily uses arrays.

Note also that calling a generic vararg method with an explicit array parameter may silently produce different behaviour than expected:

public <T> void foo(T... params) { ... }

int[] arr = {1, 2, 3};

foo(arr); // passes an int[][] array containing a single int[] element

Thus - apart from requiring a lot of effort for no clear benefit - it is not always desirable to replace legacy array parameters with varargs.

Not to mention the cases when you can't, because there is another parameter after the array in the method parameter list:

public void foo(String[] strings, String anotherParam) { ... }

Reordering the parameters may technically solve this, however it breaks client code.

Update: Effective Java 2nd. Edition, Item 42: Use varargs judiciously explains this in more details, giving also a concrete example: Arrays.asList() was retrofitted in Java5 to have vararg parameters, which inadvertently broke a lot of existing code may cause surprises when using this (now obsolete) idiom to print an array:

System.out.println(Arrays.asList(myArray));

Update2: Double checked the source, and it says that the problem occurrs with arrays of primitive types, such as int[]. Before varargs, code like this:

int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
System.out.println(Arrays.asList(digits));

would emit a compilation error, because only arrays of reference types could be converted to a List. Since varargs, and retrofitting asList, the code above compiles without warnings, and the unintended result is something like "[[I@3e25a5]".

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • "passes a String[][] array containing a single String[] element" can't reproduce this – user102008 Aug 31 '11 at 22:53
  • 1
    To clarify, you can include another parameter in the signature that doesn't take varargs--but [the vararg-accepting parameter has to go last](http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html). Also, in the example above, calling `foo(arr);` makes the compiler generate a `String[]` containing the `String[]` that you passed in. In other words, it generates a two-dimensional `String` array, which is a `String[][]`. – hotshot309 Jan 25 '12 at 17:32
  • 3
    **Totally wrong**. Passing a non-primitive array to a varargs parameter will NOT result in a two-dimensional array! Explained [here](http://stackoverflow.com/a/2926653/159570) and easily tested. – Joe Coder Apr 15 '12 at 08:29
  • 3
    @JoeCoder, not totally wrong, only imprecise. Please see my update. – Péter Török Apr 15 '12 at 22:34
9

The main reason not to specify everything as varargs is that it doesn't always make sense. For example, if InputStream.read(byte[]) where defined as `read(byte...) then the following call would be valid:

myInputStream.read(0, 1, 2, 3);

This would create a 4-element byte array, pass it in and then discard it.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
6

A vararg is simple syntactic sugar for an array.

if you call foo("abc", "def", "ghi"); then compiler will call it as foo(new String[] {"abc", "def", "ghi"});

compiler will create one new array and pass it to foo(). One can't have both foo(String...) and foo(String[]). Since both are functionally same.

Prince John Wesley
  • 62,492
  • 12
  • 87
  • 94
3

in foo you specify three params, you would have to call bar like this:

 bar(new String[]{"abc", "def", "ghi"});

so that you only call it with one parameter, that is the String[] in this case this has alsmost nothing to do with internals, your method signature for the method bar simply states that it only has one param, whereas foo has n params which are all strings

sharpner
  • 3,857
  • 3
  • 19
  • 28
2

This is, how varargs are defined. The varargs extension do not make every array accepting function a varargs function. You have to call bar like this:

bar(new String[]{"abc", "def", "ghi"})
Daniel
  • 27,718
  • 20
  • 89
  • 133
-1

Another difference is efficiency. Objects that are inside an explicit array won't get invoked. However the parameters of a variable argument list are evaluated when the method is pushed on the stack.

This is apparent when a function call is passed as a parameter that returns the type that is used in the variable argument list.

Example: someMethod( Object... x) anotherMethod( Object [] );

someMethod( a(), b(), c()); // a, b and c will be invoked before you get into the method.

anotherMethod ( new Object[]{a(), b(), c()}); // The methods aren't invoked until the objects are accessed.

Ken T.
  • 7
  • 2
  • `The methods aren't invoked until the objects are accessed`: Surprising! Does this mean if I don't access the objects in a method, they are never called? Also, did you compile and run this code to confirm the behaviour? – kevinarpe Aug 22 '16 at 01:48
  • 1
    The reason the object parameters aren't invoked in the example I gave is because they are embedded in the object [] array. They will be invoked when the array members are processed, but not at the time of being pushed on the stack for the original method invocation. – Ken T. Oct 05 '16 at 22:34
  • Perhaps I am mistaken, but I believe this to be incorrect: Java is an eagerly-evaluated language. Take a look at [this](https://pastebin.com/raw/emX67Sb6) code for instance. ([tio.run link](https://tio.run/##hZC9jsIwEIR7nmLPVawDS9RU/DQUVJSIYkksWHAMsjeJEMqzB4cYiDjp2G6l@WZn54gljo7ZqWlSg97DCsnCbQBwcVQia/CMTCmQZUjRGJ0la3Zk9@DlQ9fO@upZ5@pcsAqYZWMTsYQKfUR@QMBvACZR7zQXzsK43evB32PlmTIo0RFmlCbBUCkF6Pa9k53FvwYV8WHqHF5bh832i0GxMwHs83moIj77Qb@ixUbEVMjhsx4xEzJ@@k5gdQVdittLN@9DCyGhll2cumnu)) – Quelklef Apr 22 '21 at 20:52