1. Overview
In this tutorial, we’ll explore different approaches to supply a Collection as an argument for a varargs parameter.
2. What’s a Varargs Parameter?
Variable arguments, or varargs for short, were introduced in Java 5. We can easily identify it by its distinctive syntax of three dots when declaring a method parameters type:
public void method(String... strings) {}
A variable argument allows us to pass any number of variables of the same type to a method. For example, if we had three String variables we could pass these directly when invoking our method:
method(s1, s2, s3);
Under the hood, an array is instantiated and populated from the arguments passed.
3. Understanding the Problem
As we’ve demonstrated, invoking a method with a varargs parameter is easy when we have distinct variables to pass. However, we may find that our variables are contained in a Collection instead.
Let’s suppose we have a List of Strings, as we explore different ways to pass this Collection to a varargs parameter:
List<String> listOfStrings = List.of(s1, s2, s3);
4. Using Traditional for Loop to Populate Array
We can use the traditional for loop to populate an array from our List. We can then pass this array to our method directly:
@Test
void givenList_whenUsingForLoopToPopulateArray_thenInvokeVarargsMethod() {
String[] array = new String[listOfStrings.size()];
for (int i = 0; i < listOfStrings.size(); i++) {
array[i] = listOfStrings.get(i);
}
assertDoesNotThrow(() -> method(array));
}
As we see above, we iterate over the elements in our List and use the index to place them into our new array. Notably, we wouldn’t be able to use this approach for an unordered Collection such as a Set. Thus, the next approach offers us more flexibility.
5. Using the Collection.toArray() Method
Every subtype of Collection must implement the toArray() methods. *By using the toArray(T[] a) overload, we can obtain an array directly and pass the array to a varargs method parameter:*
@Test
void givenList_whenUsingCollectionToArray_thenInvokeVarargsMethod() {
assertDoesNotThrow(() -> method(listOfStrings.toArray(new String[0])));
}
Here, we could’ve also used the default toArray(IntFunction<A[]> generator) method:
method(listOfStrings.toArray(String[]::new));
This method also allows us to supply the array to be populated from the Collection elements via a constructor reference instead. As a result, either way, we obtain an array of the desired type without the need for any casting. This wouldn’t be the case if we used the toArray() method which just returns an Object array.
6. Using the Stream.toArray() Method
A different approach would be to obtain an array from our List by utilizing the toArray(IntFunction<A[]> generator) method of the Stream class:
@Test
void givenList_whenUsingStreamAPI_thenInvokeVarargsMethod() {
String[] array = listOfStrings.stream().toArray(String[]::new);
assertDoesNotThrow(() -> method(array));
}
As we can see, we obtain a stream from our List and invoke the terminal operation toArray() to collect the elements into an array. Additionally, we also need to supply here the function to instantiate our desired array.
Functional programming can be very powerful if we need to incorporate filtering or transforming logic on our elements. Therefore, we can easily implement this through the use of the intermediate map() and filter() operations.
7. Conclusion
In this article, we explored what a varargs parameter is and how it works under the hood. Consequently, this allowed us to explore different ways to pass a Collection to a varargs parameter. Furthermore, we briefly introduced functional programming within Java by exploring the Stream API.
As always, the code samples used in this article are available over on GitHub.