Java Varargs (Variable Arguments) - Ellipsis Parameter - Vararg Examples

1. Varargs (Variable Arguments) Introduction

If you ask that what the three dots or ellipsis mean in methods' parameter definitions in Java, now we know that, this is called "varargs" (Variable Arguments).

Varargs, which exists in many programming languages and it is introduced to Java with Java 5 version. Varargs basically allows for a method that took an arbitrary number of values to be defined as a single parameter (technically as an array) in the method.

2. Advantage of Using Varargs and When May Use It

  • Before the varargs, a method that took an arbitrary number of values needed us to create an array with the proper values. Then, method could have been invoked with an array as an argument.
 public static void main(String[] args) {
        int[] intArray = { 20, 30, 40};
        display(intArray);
    }
    
    public static void display(int[] intArray){
	//
    }

With Varargs:

    public static void main(String[] args) {
        display(20, 30, 40);
    }
    
    public static void display(int... intArray){
	//
    }
  • Varargs can be used when we are unsure the number of same type arguments to pass a method.
public void display(String val1, String val2, String val3, String val4,....)
public void display(String... values)
  • Less code can be written for method overloading cases. There may no need to define methods as the same name with different parameters.

Example of Method Overloading usage;

public String display()
 { ... }


public String display(String value)
 { ... }


public String display(String value, String value2)
{ ... }

Varargs Simplification:

public String display(String... values)
{ ... }

3. Varargs Usage and Identification Rules

When we use varargs, the Java compiler creates an array to hold the values.

Let's take the following code example;

displayStringValues(String... values)

Using varargs (...) tells the compiler that the "varargs" parameter is used. Consequently, the variable "values" ​​is defined as an array of type "String[] values".

3.1 Varargs parameter

  • It is basically an array parameter.
  • Can be called with zero argument for varargs parameter. (No need to pass any value)
  • Can be called with one or more than one arguments for varargs parameter.

3.2 Varargs Tanımlama Kuralları

  • A method can only have one varargs parameter
  • The varargs parameter must be defined as last parameter in the method.

4. Varargs Example

Let's define a method with varargs parameter as displayStringValues(String... values). The inside of this method,  let's print the total number of arguments and each passed arguments to the console.

    public static void displayStringValues(String... values) {
        System.out.println("Number of arguments - [values_length]: " + values.length);
        for (String value : values) {
            System.out.print(value + " ");
        }
        System.out.println(); // For output
    }

Let's call the defined method in 3 different ways and examine the results.

public static void main(String[] args) {
        displayStringValues();
        displayStringValues("A");
        displayStringValues("A", "B", "1", "2");
    }

Output:

Number of arguments - [values_length]: 0

Number of arguments - [values_length]: 1
A 
Number of arguments - [values_length]: 4
A B 1 2 
  • displayStringValues(); - No value passed. It is added as an empty "String[]" array to the varargs parameter in the method.
  • displayStringValues("A"); -  "A" value passed to varargs parameter. Thus, "A" is passed as String[] Array - String[{A}]
  • displayStringValues("A", "B", "1", "2"); -  "A", "B", "1", "2" values passed to varargs parameter. Thus, those values  passed/added as String[] Array - String[{A, "B", "1", "2"}]

5. Varargs Usage Examples:

5.1 Method Overloading and Different Varargs Data Types

Let's define two methods named displayData, one of them is displayData(String... values) of  String type and the other one is displayData(int... values) of int type.

    public static void displayData(String... values) {
        System.out.println("[STRING] Number of arguments - [values.length]: " + values.length);
        for (String value : values) {
            System.out.println(value + " ");
        }
    }
String... values
    public static void displayData(int... values) {
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }
int... values

Let's call these methods from the Main method as follows;

public static void main(String[] args) {
        displayData("A", "B");
        displayData(1, 2);
    }

Output:

[STRING] Number of arguments - [values.length]: 2
A 
B 
[INT] Number of arguments [values.length]: 2
1 
2 

Çalışma (Runtime) anında, belli tipte

  • With displayData("A", "B"); -> displayData(String... values) is called.
  • With displayData(1, 2); ->  displayData(int... values) is called.

As we can see, there is no problem.

5.1.2 - Varargs - Method Overloading Ambiguity Problem

We will consider the above example in a different situation. Let's define the methods void displayData(int... values) and void displayData(String... values) as in the example above.

 public static void displayData(int... values) {
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

    public static void displayData(String... values) {
        System.out.println("[STRING] Number of arguments - [values.length]: " + values.length);
        for (String value : values) {
            System.out.println(value + " ");
        }
    }

from main method;

public static void main(String[] args) {
        displayData();
    }

displayData(); - when we want to call this method

Output:

java: reference to displayData is ambiguous
  both method displayData(int...) in Main and method displayData(java.lang.String...) in Main match

this compiler error will occur.

Because there are two methods with the same name.  Parameterless method call causes ambiguous at the compile time.

5.1.2.2 Inappropriate Parameters

Most of the time, this scenario is warned by the compiler. But it is another error that will be detected at the compile time.

For the same example above, When a method is called with displayData(1,"A");

    public static void main(String[] args) {
        displayData(1,"A");
    }

Output:

java: no suitable method found for displayData(int,java.lang.String)
    method Main.displayData(int...) is not applicable
      (varargs mismatch; java.lang.String cannot be converted to int)
    method Main.displayData(java.lang.String...) is not applicable
      (varargs mismatch; int cannot be converted to java.lang.String)

It tried to suitability for both methods. Those values could not pass to those varargs parameters


5.2 Metot Overloading - Varargs and Array Parameter Definitions

Let's define two different methods with the same name as displayData(String... values) and displayData(String[] values).

    public static void displayData(String... values) {
        System.out.println("[STRING] Number of arguments - [values.length]: " + values.length);
        for (String s : values) {
            System.out.println(s + " ");
        }
    }

    public static void displayData(String[] values) {
        System.out.println("[STRING] Number of arguments - [values.length]: " + values.length);
        for (String s : values) {
            System.out.println(s + " ");
        }
    }
    public static void main(String[] args) {
        displayData("A", "B");
    }
  • When we call it from main method displayData("A", "B"); the following error will be occured:

Output:

java: cannot declare both displayData(java.lang.String[]) and displayData(java.lang.String...) in Main

The reason is, we said that Varargs is an array parameter.

  • displayData(String[] values) -> String[] is a String type array parameter as values.
  • displayData(String... values) -> String... values - Although it is a varargs parameter, the "values" will actually hold is a type of String array (String[])

5.3 Varargs Çoklu Paramatre Kullanımı

To remind the rules about Varargs;

A method can only have one varargs parameter
The varargs parameter must be defined as last parameter in the method.

5.3.1 Varargs Multiple Parameter Example

Let's define the method displayData(int intVal, int... values) in accordance with two rules.

  • Its first parameter is int intVal and its second parameter is a vararg parameter as int... values.
    public static void displayData(int intVal, int... values) {
        System.out.println("intVal value: " + intVal);
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

Let's call the method from the main Method

    public static void main(String[] args) {
        displayData(10);
    }

Output:

intVal value: 10
[INT] Number of arguments [values.length]: 0
  • With displayData(10); - The first parameter is passed with a value, and the second parameter remains an empty array.

Let's call the same method as displayData(1, 2, 3, 4);

    public static void main(String[] args) {
        displayData(1, 2, 3, 4);
    }

Output:

Val1 value: 1
[INT] Number of arguments [values.length]: 3
2 
3 
4 

When displayData(int intVal, int... values) method is called with displayData(1, 2, 3, 4);

  • In the order of the parameters, the value "1" is passed to the "intVal" parameter.
  • The int values - "2", "3", "4" are passed  to the varargs int... values  parameter as an array.

5.3.2 Varargs Multiple Parameter Example - 2

Similar to 5.3.1 example, Let's definedisplayData(int intVal, String strVal, int... values) method.

    public static void displayData(int intVal, String strVal, int... values) {
        System.out.println("Val1 value: " + intVal);
        System.out.println("Val1 value: " + strVal);

        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }
    public static void main(String[] args) {
        displayData(10, "Volkan");

    }

Output:

intVal value: 10
strVal value: Volkan
[INT] Number of arguments [values.length]: 0

With the same method we call it as;

    public static void main(String[] args) {
        displayData(10, "Volkan", 100, 1000);
    }

Output:

intVal value: 10
strVal value: Volkan
[INT] Number of arguments [values.length]: 2
100 
1000 

Note: More than one variable (String, int, long etc.) can be defined before Varargs parameter. As we remember from the rule, the varargs parameter has to be added last in the method. As we can see in the previous examples, it is not mandatory to pass a value to the vararg parameter.


5.4 Method Overloading - Using Multiple Parameters

Let's define displayData(int... values) and displayData(int val1, int... values) methods with the name of displayData.

    public static void displayData(int... values) {
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int i : values) {
            System.out.println(i + " ");
        }
    }


    public static void displayData(int intVal, int... values) {
        System.out.println("Val1 value: " + intVal);
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

Let's call displayData(); from main method.

    public static void main(String[] args) {
        displayData();
    }

Output:

[INT] Number of arguments [values.length]: 0

There is no problem because:

  • Since we are sending without parameters,  displayData(int... values) method is a proper and was called.

But if, If we try to call it with:

    public static void main(String[] args) {
        displayData(1);
    }

or

    public static void main(String[] args) {
        displayData(10, 20, 30, 40);
    }

Output;

java: reference to displayData is ambiguous
  both method displayData(int...) in Main and method displayData(int,int...) in Main match

The "ambiguity" error will be received during compilation.

Sent a value of 1 when called with display Data(1);

  • A value of "1" for displayData(int intVal, int... values) is an appropriate value pass to the intVal parameter. It is not mandatory to send a value for the Varargs parameter.
  • It is also a suitable value pass to the displayData(int... values) method.

In case of displayData(10, 20, 30, 40); called,  (10, 20, 30, 40) values are passed to ;

  • For the method of displayData(int intVal, int... values),  int value of "10" is suitable value passing for intVal. "20, 30, 40" values are suitable value passing for type of  int ... values Varargs parameter.
  • These values are also suitable value passes to the displayData(int... values) method.

For this reason, ambiguity error is received at compile time.

To solve this problem;

Defining an int array and sending that array to the varargs parameter will solve the problem.

    public static void main(String[] args) {

        int[] intArray = { 20, 30, 40};
        displayData(10, intArray);

    }

Output:

Val1 value: 10
[INT] Number of arguments [values.length]: 3
20 
30 
40 
  • int[] intArray = { 20, 30, 40}; - We have defined an int array.
  • displayData(10, intArray); - An appropriate method call with it.
  • Since the varargs parameter is an array of the corresponding type, then method calling to match will be method of displayData(int val1, int... values).

In this way, ambiguity problem in compile time is solved.


5.5 Combining Array and Varargs Parameter

Let's define a method displayData(int[] intArray, int... values)

    public static void displayData(int[] intArray, int... values) {
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
        System.out.println("[INT] Number of arguments [intArray.length]: " + intArray.length);
        for (int value : intArray) {
            System.out.println(value + " ");
        }
    }
5.5.1 Example of method calling - 1

Into the main method;

  public static void main(String[] args) {

        int[] intArr = {1, 2};
        displayData(intArr);

    }

Output;

[INT] Number of arguments [values.length]: 0
[INT] Number of arguments [intArray.length]: 2
1 
2 

To displayData(int[] intArray, int... values) method,  with invoking of displayData(intArr); .

  • intArrarray is passed to the first parameter in the defined method.
5.5.2 Example of method calling - 2
    public static void main(String[] args) {

        int[] intArr = {1, 2};
        displayData(intArr, 10, 20, 30);

    }

Output:

[INT] Number of arguments [values.length]: 3
10 
20 
30 
[INT] Number of arguments [intArray.length]: 2
1 
2 

To displayData(int[] intArray, int... values) method with invoking of  displayData(intArr, 10, 20, 30);

  • intArrarray is passed to the first parameter in the defined method.
  • The argument values 10, 20, 30 are passed to the second varargs parameter int... values as an int array.
5.5.3 Example of method calling - 3
public static void main(String[] args) {

        int[] intArr = {1, 2};
        displayData(intArr, intArr);

    }

Output;

[INT] Number of arguments [values.length]: 2
1 
2 
[INT] Number of arguments [intArray.length]: 2
1 
2 

To displayData(int[] intArray, int... values) method, with invoking of displayData(intArr, intArr);

  • intArrarray is passed to the first parameter in the defined method.
  • intArr array is likewise passed to the second varargs parameter int... values as an int array.

5.6 Using VarArgs with a Two-Dimensional Array

Let's define two different methods with the same name, displayData(int... values) and displayData(int[]... values)

public static void displayData(int... values) {
        System.out.println("displayData(int... values)");
        for (int intVal : values)
            System.out.println(intVal);
    }

    public static void displayData(int[]... values) {
        System.out.println("displayData(int[]... values)");
        for (int[] array : values)
            for (int intVal : array)
                System.out.println(intVal);
    }

Let's define three different one-dimensional arrays and one two-dimensional array in the main method. And then send them to the displayData method.

 public static void main(String[] args) {
        int[] arr1 = {1, 2};
        int[] arr2 = {20};
        int[] arr3 = {100, 200};

        displayData(arr1);
        System.out.println("-----------");
        displayData(arr1, arr2);
        System.out.println("-----------");
        displayData(arr1, arr2, arr3);

        System.out.println("-----------");
        int[][] arr4 = {{1000, 2000}, {3000}};
        displayData(arr4);
        
    }

Output;

displayData(int... values)
1
2
-----------
displayData(int[]... values)
1
2
20
-----------
displayData(int[]... values)
1
2
20
100
200
-----------
displayData(int[]... values)
1000
2000
3000

Process finished with exit code 0

As can be seen from the output;

  • Only invoking of  displayData(arr1); is appropriate for displayData(int... values) method.
  • Invoking of displayData(arr1, arr2); and displayData(arr1, arr2, arr3); are appropriate for  displayData(int[]... values) method as two-dimensional array.
  • Likewise, invoking of displayData(arr4); with two-dimensional array arr4 is appropriate for displayData(int[]... values) method.

5.7  Varargs - Primitive ve Object - Wrapper Class - Metot Overloading Usage

5.7.1 Example 1

Let's define two methods.public static void displayData(int... values) and public static void displayData(Integer... values).

  public static void displayData(int... values) {
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

    public static void displayData(Integer... values) {
        System.out.println("[INTEGER] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

Main method;

public static void main(String[] args) {
        displayData(1,2);
    }

Output;

java: reference to displayData is ambiguous
  both method displayData(int...) in varr.Main and method displayData(java.lang.Integer...) in varr.Main match

Ambiguous error will be occured. Because invoking of displayData(1,2); is for both methods.

Example of the proper invoking;

    public static void main(String[] args) {
        displayData(new int[] { 1, 2, 3 });
        displayData(new Integer[] { 1, 2, 3 });
    }

Output;

[INT] Number of arguments [values.length]: 3
1 
2 
3 
[INTEGER] Number of arguments [values.length]: 4
4 
5 
6 
7 
5.7.2 Varargs Usage - Object and Primitive Type

Let's definepublic static void displayData(int... values) and public static void displayData(Object... values)

public static void displayData(int... values) {
        System.out.println("[INT] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

    public static void displayData(Object... values) {
        System.out.println("[OBJECT] Number of arguments - [values.length]: " + values.length);
        for (Object value : values) {
            System.out.println(value + " ");
        }
    }

Let's invoke displayData(1, 2, 3) from main method.

    public static void main(String[] args) {
        displayData(1, 2, 3);
    }

"ambiguous" error occured during compile time.

java: reference to displayData is ambiguous
  both method displayData(int...) in varr.Main and method displayData(java.lang.Object...) in varr.Main match

If method invoking would have been called via int array.

    public static void main(String[] args) {
        displayData(new int[]{1, 2, 3});
    }

Output:

[INT] Number of arguments [values.length]: 3
1 
2 
3 

If only the void displayData(Object... values) method were to be defined.

    public static void main(String[] args) {
        displayData(1, 2, 3);
        displayData(new int[]{3, 4, 5});
    }

    public static void displayData(Object... values) {
        System.out.println("[OBJECT] Number of arguments - [values.length]: " + values.length);
        for (Object value : values) {
            System.out.println(value + " ");
        }
    }

Output:

[OBJECT] Number of arguments - [values.length]: 3
1 
2 
3 
[OBJECT] Number of arguments - [values.length]: 1
[I@3b07d329 

With the invoking ofdisplayData(1, 2, 3); we have written all the relevant values in the console.

With the invoking of displayData(new int[]{3, 4, 5});, The array of type int has been completely added to displayData(Object... values) method's parameter as the first element of the Object Array. .("Confusing primitive array argument to varargs method")

This "confusing" situation will not be seen in the next example of Wrapper Class.

5.7.3 Vargargs Usage - Object and Wrapper Class

Let's define void displayData(Integer... values) and void displayData(Object... values) methods;

 public static void displayData(Integer... values) {
        System.out.println("[INTEGER] Number of arguments [values.length]: " + values.length);
        for (int value : values) {
            System.out.println(value + " ");
        }
    }

    public static void displayData(Object... values) {
        System.out.println("[OBJECT] Number of arguments - [values.length]: " + values.length);
        for (Object value : values) {
            System.out.println(value + " ");
        }
    }
public static void main(String[] args) {
        displayData(1, 2, 3);
    }

Output:

[INTEGER] Number of arguments [values.length]: 3
1 
2 
3 

Diğer bir senaryo olarak aynı tanımlanmış metotları üç farklı şekilde çağıralım;

As another scenario, let's invoke the display method with three different ways.

    public static void main(String[] args) {
        displayData(1, 2, 3);
        displayData(new Integer[]{3, 4, 5});
        displayData(new int[]{3, 4, 5});
    }

Output:

[INTEGER] Number of arguments [values.length]: 3
1 
2 
3 
[INTEGER] Number of arguments [values.length]: 3
3 
4 
5 
[OBJECT] Number of arguments - [values.length]: 1
[I@7ba4f24f 
  • With the invoking of displayData(1, 2, 3);, 1,2,3 values are added to displayData(Integer... values) method's parameter as an Integer[] array.
  • The same way, with the invoking of displayData(new Integer[]{3, 4, 5});, all related values are added to displayData(Integer... values) method's parameter and are written in the console.
  • With the invoking of displayData(new int[]{3, 4, 5});,  The array of type int has been completely added to displayData(Object... values) method's parameter as the first element of the Object Array.

Conclusion

In this article, we learned what the Vararg parameter is basically and its definition rules. We have mentioned various scenarios with usage examples and mentioned some error cases.

References
https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html
https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html#varargs