W3docs

Java Varargs (Variable-Length Arguments)

Define Java methods that accept any number of arguments with varargs (Type... name). Learn the rules, calling conventions, overloading, and common gotchas.

A varargs parameter (short for variable-length arguments) lets a method accept any number of arguments — zero, one, ten, a hundred — of the same type, without forcing the caller to bundle them into an array first. You write the last parameter as Type... name, and inside the method name is an ordinary array of that type.

You've used varargs methods for years. String.format("%s + %s = %s", a, b, c) accepts however many substitution values the format string needs. List.of(1, 2, 3, 4, 5) accepts an arbitrary list of elements. Both rely on varargs.

Declaring a varargs parameter

The syntax is three dots between the element type and the parameter name:

public static int sum(int... numbers) {
  int total = 0;
  for (int n : numbers) total += n;
  return total;
}

Callers pass any number of int arguments:

sum();              // 0
sum(5);             // 5
sum(1, 2, 3);       // 6
sum(1, 2, 3, 4);    // 10

Inside the method, numbers is an int[]. The compiler bundles the loose arguments into an array at the call site.

Varargs is just an array

The body treats the varargs parameter exactly like an array — .length, indexing, for-each, everything:

public static String join(String sep, String... parts) {
  if (parts.length == 0) return "";
  StringBuilder sb = new StringBuilder(parts[0]);
  for (int i = 1; i < parts.length; i++) {
    sb.append(sep).append(parts[i]);
  }
  return sb.toString();
}

join(", ", "red", "green", "blue");   // "red, green, blue"
join("-");                            // ""

Because the parameter is an array, you can also pass a literal array directly:

String[] colors = {"red", "green", "blue"};
join(", ", colors);                   // same as join(", ", "red", "green", "blue")

The compiler accepts either form.

The rules

A few constraints come with the syntax:

  • A method may have at most one varargs parameter. Two would be ambiguous.
  • It must be the last parameter. Otherwise the compiler couldn't tell where the variable arguments end and the next parameter begins.
  • Other parameters come first. Fixed parameters in front, varargs at the tail.
// VALID
public static String tag(String name, String... attrs)   { ... }
public static int    sum(int initial, int... rest)        { ... }

// INVALID
// public static int sum(int... a, int... b)              // two varargs
// public static int sum(int... a, int b)                 // varargs not last

Calling varargs methods

You can pass:

  1. Loose valuesf(1, 2, 3).
  2. An array of the right typef(new int[]{1, 2, 3}).
  3. Nothing at allf(). The method receives an array of length 0, not null.
sum();                       // numbers is int[0]
sum(new int[0]);             // also int[0]
sum(new int[]{1, 2, 3});     // numbers is int[]{1,2,3}

A null argument is a tricky case: sum(null) compiles, treats null as the array itself, and the loop throws NullPointerException. Most varargs methods don't expect null.

Varargs and overloading

When you overload a method, varargs versions are checked last. A non-varargs (fixed-arity) overload that matches will be preferred:

public static void show(int a, int b)    { System.out.println("two ints"); }
public static void show(int... xs)        { System.out.println("varargs"); }

show(1, 2);       // "two ints" — fixed-arity wins
show(1);          // "varargs"  — no fixed match
show(1, 2, 3);    // "varargs"

This is good — varargs is the fallback, used only when nothing more specific fits.

A common gotcha: Object...

Varargs of Object accepts anything, including an array:

public static void log(Object... values) {
  for (Object v : values) System.out.println(v);
}

log("a", 1, 2.5);            // 3 calls
String[] names = {"Ada", "Bob"};
log(names);                   // ONE Object[] argument, prints "Ada" then "Bob"
log((Object) names);          // ONE Object argument, prints "[Ljava.lang.String;@..."

The compiler chooses whichever interpretation produces a valid call. With Object..., both interpretations work, and the rules tip towards "treat the array as the varargs array." If you want the array as a single element, cast it: log((Object) names).

When (not) to use varargs

Varargs is a convenience at the call site, not a free abstraction. Every call that passes loose values allocates a fresh array behind the scenes. For methods called in tight loops on a hot path, that allocation can add up — which is why the standard library sometimes ships fixed-arity overloads alongside the varargs version. List.of is the classic example: it has dedicated overloads for of(), of(e1), of(e1, e2) up to ten elements, and only falls back to a varargs of(E... elements) beyond that.

For everyday code the cost is negligible, and clarity wins. Reach for varargs when:

  • the number of arguments genuinely varies (formatting, logging, building collections);
  • forcing the caller to write new Type[]{...} would be noise.

Prefer a plain array or a List parameter when the caller usually already has a collection in hand, or when you want to make "pass many values" the explicit, expected case.

A worked example

java— editable, runs on the server

What's next

You can now write methods with the full range of parameter shapes Java offers — fixed, overloaded, recursive, and varargs. The final chapter of the methods part returns to the one method every program has: the main method — whose String[] args can equally be written String... args — and what its signature really tells the JVM.

Practice

Practice
Inside a method declared as void f(int... xs), what is the type of xs when no arguments are passed?
Inside a method declared as void f(int... xs), what is the type of xs when no arguments are passed?
Was this page helpful?