
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: January 8, 2024
Varargs were introduced in Java 5 and provide a short-hand for methods that support an arbitrary number of parameters of one type.
In this article, we’ll see how we can use this core Java feature.
Before Java 5, whenever we wanted to pass an arbitrary number of arguments, we had to pass all arguments in an array or implement N methods (one for each additional parameter):
public String format() { ... }
public String format(String value) { ... }
public String format(String val1, String val2) { ... }
Varargs help us avoid writing boilerplate code by introducing the new syntax that can handle an arbitrary number of parameters automatically – using an array under the hood.
We can define them using a standard type declaration, followed by an ellipsis:
public String formatWithVarArgs(String... values) {
// ...
}
And now, we can call our method with an arbitrary number of arguments, like:
formatWithVarArgs();
formatWithVarArgs("a", "b", "c", "d");
As mentioned earlier, varargs are arrays so we need to work with them just like we’d work with a normal array.
Varargs are straightforward to use. But there’re a few rules we have to keep in mind:
Using varargs can lead to so-called Heap Pollution. To better understand the heap pollution, consider this varargs method:
static String firstOfFirst(List<String>... strings) {
List<Integer> ints = Collections.singletonList(42);
Object[] objects = strings;
objects[0] = ints; // Heap pollution
return strings[0].get(0); // ClassCastException
}
If we call this strange method in a test:
String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList());
assertEquals("one", one);
We would get a ClassCastException even though we didn’t even use any explicit type casts here:
java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String
Every time we use varargs, the Java compiler creates an array to hold the given parameters. In this case, the compiler creates an array with generic type components to hold the arguments.
When we use varargs with generic types, as there’s a potential risk of a fatal runtime exception, the Java compiler warns us about a possible unsafe varargs usage:
warning: [varargs] Possible heap pollution from parameterized vararg type T
The varargs usage is safe if and only if:
If we are sure that the method itself does safely use the varargs, we can use @SafeVarargs to suppress the warning.
Put simply, the varargs usage is safe if we use them to transfer a variable number of arguments from the caller to the method and nothing more!
Let’s consider another unsafe usage of varargs:
static <T> T[] toArray(T... arguments) {
return arguments;
}
At first, it might seem that the toArray method is completely harmless. However, because it let the varargs array escape to the caller, it violates the second rule of safe varargs.
To see how this method can be dangerous, let’s use it in another method:
static <T> T[] returnAsIs(T a, T b) {
return toArray(a, b);
}
Then if we call this method:
String[] args = returnAsIs("One", "Two");
We would, again, get a ClassCastException. Here’s what happens when we call the returnAsIs method:
For a more detailed discussion on heap pollution, it’s highly recommended to read item 32 of Effective Java by Joshua Bloch.
Varargs can make a lot of boilerplate go away in Java.
And, thanks to their implicit autoboxing to and from Array, they play a role in future-proofing our code.