Java Varargs
Table of Contents + β
In the last lesson you learned about Java method overloading. But what if you do not know how many values the caller will pass? Java solves this with varargs, short for variable arguments, which let a method take any number of values.
π€ Why do we need varargs?
Say you want a sum method that adds however many numbers someone gives it. Without varargs you are stuck:
- Overload once per count? There is no last version. Someone always wants one more number.
// β This never ends. You cannot cover every possible count.static int sum(int a, int b) { ... }static int sum(int a, int b, int c) { ... }static int sum(int a, int b, int c, int d) { ... }// ... forever- Force the caller to build an array? That pushes clunky work onto every caller.
You cannot know in advance how many arguments the caller has, so a fixed parameter list does not fit. Varargs fix this: one method takes two numbers or fifty, and the caller just passes as many as they want.
Picture a shop checkout. The cashier does not need to know your item count before you arrive. Two items or twenty, same cashier. Varargs are that cashier.
π§© The varargs syntax
Write three dots ... right after the type. That is the whole syntax.
// The ... means "any number of values of this type".returnType methodName(Type... name) { // name behaves like an array here}Read int... numbers as βany number of intsβ. When the caller passes several loose values, Java collects them into an array and hands it to your method:
numbersinside the method is just anint[].- Loop over it with a for-each or an index.
- Read the count with
.length. - Index into it, like
numbers[0], for a specific position.
π‘ A sum method with varargs
This sum takes any number of ints and adds them all.
public class Adder {
// int... numbers means "any number of ints", arriving as an array. static int sum(int... numbers) { int total = 0; for (int n : numbers) { // β
numbers is just an int[] inside total = total + n; } return total; }
public static void main(String[] args) { System.out.println(sum(5, 3)); // two values System.out.println(sum(1, 2, 3, 4, 5)); // five values System.out.println(sum()); // even zero values }}sum(int... numbers)declares one varargs parameter that serves every call.numbersis an array, so the for-each adds each value tototal.- The calls pass two, five, and zero ints.
- Zero arguments give an empty array, so the loop runs zero times and
totalstays 0.
Output
8150The third line is 0. Calling sum() with nothing did not crash and did not give null. It gave an empty array, which summed to zero.
π It really is an array inside
The varargs parameter is a real array inside the method, with a real .length you can loop and index. Everything you know about arrays just works. Here a method lists any number of words.
public class Printer {
static void show(String... words) { // words is a String[] here, so .length and looping both work. System.out.println("You passed " + words.length + " words:"); for (String w : words) { System.out.println("- " + w); } }
public static void main(String[] args) { show("apple", "banana", "cherry"); }}show(String... words)accepts any number of strings, arriving as aString[].words.lengthgives the count, so we print3.- The for-each prints each word with a dash in front.
The ... is a convenience for the caller, not the method. It lets them pass loose values instead of building an array by hand.
Output
You passed 3 words:- apple- banana- cherryBecause it is a real array, you can pass a ready-made String[] straight in. No unpacking needed.
public class PassArray {
static void show(String... words) { for (String w : words) { System.out.println("- " + w); } }
public static void main(String[] args) { String[] fruits = { "apple", "banana", "cherry" }; show(fruits); // β
passing a ready-made array also works }}So a varargs method accepts both styles: loose values like show("apple", "banana"), or a finished array like show(fruits). Both reach the method as the same String[].
π¨οΈ The printf-style example
You have already used varargs: System.out.printf is one. The format text comes first, then any number of values to drop into it. This method follows the same shape: a label, then any number of scores.
public class Report {
// label is fixed and first; scores is varargs and last. static void printScores(String label, int... scores) { System.out.println(label + " (" + scores.length + " scores):"); for (int s : scores) { System.out.println(" " + s); } }
public static void main(String[] args) { printScores("Riya", 90, 85, 100); printScores("Alex"); // no scores yet, that is fine }}labelis a fixed parameter, so the first argument fills it.scoresis varargs, so every argument after the label lands in thescoresarray.- The second call gives only a label, so
scoresis empty and the loop prints nothing.
Same shape as printf: one fixed thing in front, then a flexible tail of values.
Output
Riya (3 scores): 90 85 100Alex (0 scores):Here is the real printf. The %s and %d are placeholders, and the loose values after the text fill them in order.
String name = "Alex";int score = 90;// printf takes the text first, then any number of values to insert.System.out.printf("%s scored %d%n", name, score);Output
Alex scored 90Varargs are everywhere: printf, String.format, and List.of all use them.
π The rules of varargs
Break these and the code will not compile:
- A method can have only one varargs parameter.
- The varargs parameter must be the last one. Fixed parameters come first.
- Both rules exist so Java can tell where the loose values stop and start. Two varargs, or one in the middle, would be ambiguous.
Here is a valid mix of a fixed parameter and varargs.
public class Greeter {
// β
fixed parameter first, varargs last static void greet(String greeting, String... names) { for (String name : names) { System.out.println(greeting + ", " + name + "!"); } }
public static void main(String[] args) { greet("Hello", "Riya", "Arjun", "Alex"); }}greetingis the fixed parameter, so it grabs the first argument,"Hello".namesis varargs and last, so everything after is bundled into it.- The loop greets each name with the shared greeting.
Output
Hello, Riya!Hello, Arjun!Hello, Alex!π Varargs and overloading
Varargs are greedy: sum(int... nums) matches zero, one, two, or more ints, so it overlaps almost any other sum. When two methods both fit a call, Java prefers a fixed-parameter method over a varargs method. Varargs are the fallback, used only when no exact match exists.
public class Overloaded {
static void show(int a, int b) { System.out.println("fixed two-int version"); }
static void show(int... nums) { System.out.println("varargs version, count = " + nums.length); }
public static void main(String[] args) { show(1, 2); // two ints: exact fixed match wins show(1, 2, 3); // three ints: only varargs fits show(); // zero ints: only varargs fits }}show(1, 2)matches the fixed two-int method exactly, so Java picks that.show(1, 2, 3)has no fixed match, so varargs takes it.show()has no fixed match, so varargs takes it with an empty array.
Output
fixed two-int versionvarargs version, count = 2varargs version, count = 0Mixing them is fine as long as the fixed version wins ties. The danger is when two overloads match equally well and Java cannot choose, which is the next trap.
β οΈ Common Mistakes
Putting varargs before another parameter. The ... must be last. Anything after it confuses Java about where the loose values end.
// β Does not compile: varargs is not laststatic void greet(String... names, String greeting) { }
// β
Fixed parameter first, varargs laststatic void greet(String greeting, String... names) { }Using more than one varargs. A method gets only one ... parameter. Java could not split the loose values between two.
// β Does not compile: two varargs parametersstatic void mix(int... a, int... b) { }
// β
Only one varargs; combine the rest into itstatic void mix(int... all) { }Writing ambiguous overloads. If two overloads match a call equally well, Java refuses to guess and the code will not compile.
// β Ambiguous: which one should join("x") pick? Both fit equally.static void join(String first, String... rest) { }static void join(String... all) { }
// β
Keep one clear signature insteadstatic void join(String... all) { }The fix is to drop one clashing overload, or give them clearly different fixed parameters.
Forgetting it can be empty. Zero values give an empty array, never null. No null check needed; the loop just runs zero times.
// β
Safe with zero arguments: nums is empty, not nullstatic int sum(int... nums) { int total = 0; for (int n : nums) total += n; // runs zero times when empty return total;}β Best Practices
- Use varargs when the count truly varies. Summing numbers, joining words, logging several values.
- Keep the varargs parameter last. Put every required parameter before it.
- Treat it as an array inside. Reach for
.lengthand a loop. - Avoid overloading a varargs method. If you must, keep one overload a clearer match to dodge the ambiguity error.
- Do not reach for varargs by reflex. If you always pass exactly two values, plain parameters are clearer and safer.
π§© What Youβve Learned
- β
Varargs let a method accept any number of arguments, written with
Type.... - β
Inside the method, the varargs parameter behaves exactly like an array, with
.length, indexing, and loops. - β The caller can pass zero, one, or many loose values, or even an existing array; zero gives an empty array, not null.
- β A method can have only one varargs parameter, and it must be the last one.
- β
You can mix fixed parameters first, then the varargs at the end, just like
printf. - β When overloading, Java prefers a fixed-parameter match over varargs, and refuses to compile ambiguous overloads.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does varargs let a method do?
Why: Varargs let one method take a variable number of arguments, from zero to many.
- 2
How is the varargs parameter treated inside the method?
Why: Java bundles the passed values into an array, so you loop and index it like any array.
- 3
Where must the varargs parameter appear in the parameter list?
Why: The varargs parameter must be the last one, with fixed parameters before it.
- 4
When both a fixed-parameter method and a varargs method match a call, which does Java pick?
Why: Java prefers the exact fixed-parameter match and uses varargs only as a fallback.
π Whatβs Next?
With methods behind you, the next step is bundling data and behavior into your own types. That is what classes are about, and they are the doorway to object-oriented programming in Java.