Using Ellipsis to Accept a Variable Number of Arguments in Java
Java's varargs (short for variable arguments) let a method accept an arbitrary number of parameters of the same type. The feature was introduced in Java 5 via the ... ellipsis syntax and is now ubiquitous β String.format, Arrays.asList, List.of and Collections.addAll all rely on it.
Basic syntax
Place three dots between the type and the parameter name:
public static int sum(int... numbers) {
int total = 0;
for (int n : numbers) total += n;
return total;
}
// All of these are valid calls:
sum(); // 0
sum(1); // 1
sum(1, 2, 3); // 6
sum(new int[]{1, 2, 3}); // 6 β you can pass an array directly
Inside the method, numbers behaves as a normal int[] β the compiler wraps your arguments into an array automatically.
Rules to remember
- A varargs parameter must be the last parameter of the method signature.
- A method can have at most one varargs parameter.
- The varargs type can be any type, including objects, generics, and arrays.
// β
Legal
public void log(String level, Object... args) { }
// β Illegal: varargs must come last
public void log(Object... args, String level) { }
// β Illegal: only one varargs allowed per method
public void log(String... tags, Object... args) { }
A realistic example
A tiny logging helper that accepts a format string and any number of parameters:
public class Logger {
public static void info(String format, Object... params) {
String message = String.format(format, params);
System.out.println("[INFO] " + message);
}
public static void main(String[] args) {
info("User %s logged in from %s", "alice", "192.168.1.10");
info("Started in %d ms", 342);
}
}
Common pitfalls
Passing null to a varargs parameter
Calling doStuff(null) on a method declared as doStuff(Object... args) passes a null array, not an array containing null. Guard against it:
public void doStuff(Object... args) {
if (args == null || args.length == 0) return;
// ...
}
Overload ambiguity
Varargs methods interact oddly with overloading. The compiler prefers the most specific non-varargs match:
public static void call(int a, int b) { System.out.println("two ints"); }
public static void call(int... a) { System.out.println("varargs"); }
call(1, 2); // prints "two ints" β non-varargs wins
Generic varargs and heap pollution
Mixing varargs with generics triggers an unchecked warning because Java creates an Object[] under the hood. Use @SafeVarargs on the method if it only reads from the array:
@SafeVarargs
public static <T> List<T> listOf(T... items) {
return Arrays.asList(items);
}
When not to use varargs
If a method is called millions of times in a tight loop, the implicit array allocation can become a bottleneck. For performance-critical paths, provide fixed-arity overloads (sum(int, int), sum(int, int, int)) alongside the vararg version β this is how the JDK's List.of is implemented.
For everyday application code, varargs are idiomatic and readable. Prefer them over forcing callers to build an array manually.