Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A variable arity parameter (commonly known as varargs) is a language construct that allows a method to accept an arbitrary number of arguments of a specified type, including zero arguments. It abstracts away the boilerplate of explicitly instantiating an array when passing multiple discrete values to a method.

Syntax

A variable arity parameter is declared using an ellipsis (...) placed after the type declaration and before the variable name. Since Java 8, type annotations may be placed immediately preceding the ellipsis.
public void methodName(Type... variableName) {
    // Method body
}

public void annotatedMethod(Type @Annotation ... variableName) {
    // Method body with type annotation
}

Internal Representation

At compile time, the Java compiler translates a variable arity parameter into a standard single-dimensional array of the declared type. Within the method body, the parameter is treated exactly as an array, exposing properties like .length and allowing index-based access.
// Source code
public void processTokens(String... tokens) {
    int count = tokens.length;
    if (count > 0) {
        String firstToken = tokens[0];
    }
}

// Compiler translation (Equivalent source code)
public void processTokens(String[] tokens) {
    int count = tokens.length;
    if (count > 0) {
        String firstToken = tokens[0];
    }
}

Invocation Mechanics

When a method containing a vararg is invoked, the compiler automatically packs the provided comma-separated arguments into an array. If an array of the declared type—or a subtype, due to array covariance—is already available, it can be passed directly, bypassing the compiler’s implicit array creation. Passing null directly to a varargs method passes a null array reference, not an array containing a single null element. To pass a single null element, the argument must be explicitly cast to the component type.
public void execute(Object... values) { }

// Implicit array creation by the compiler
execute();               // Translates to: execute(new Object[0]);
execute(10, "text");     // Translates to: execute(new Object[]{10, "text"});

// Direct array passing (Array covariance)
String[] predefinedValues = {"A", "B", "C"};
execute(predefinedValues); // Passed directly without implicit wrapping

// Null behavior
execute(null);           // Passes a null array reference (values == null)
execute((Object) null);  // Passes an array with one null element: new Object[]{null}

Syntactic Constraints

The Java compiler enforces two strict rules regarding the declaration of variable arity parameters to prevent ambiguity during method resolution:
  1. Terminal Position: The vararg parameter must be the absolute last parameter in the method signature.
  2. Singularity: A method signature can declare a maximum of one vararg parameter.
// Valid declaration
public void configure(int timeout, boolean force, String... options) { }

// Compilation Error: Vararg is not the last parameter
// public void configure(String... options, int timeout) { }

// Compilation Error: Multiple vararg parameters
// public void configure(int... timeouts, String... options) { }

Method Overloading Resolution

During compilation, Java resolves overloaded methods in three distinct phases: strict invocation (which allows primitive widening conversions and reference subtyping), loose invocation (which adds boxing and unboxing), and finally, variable arity invocation. Because varargs are evaluated in the final phase, the compiler will always prioritize a method with a fixed arity signature over a variable arity signature if both are applicable.
public void calculate(long a, long b) { }    // Method A
public void calculate(int... numbers) { }    // Method B

calculate(1, 2);       // Binds to Method A (Strict invocation: int widens to long)
calculate(1, 2, 3);    // Binds to Method B (Fallback to variable arity phase)

Generics and Heap Pollution

Because varargs are implemented as arrays under the hood, combining them with non-reifiable types (such as Generics) introduces type safety vulnerabilities. Arrays in Java are covariant and retain their type at runtime, whereas Generics are subject to type erasure. Declaring a vararg of a generic type (e.g., T... elements or List<String>... lists) causes the compiler to issue a “Possible heap pollution” warning. If the method implementation guarantees that it only reads from the array and does not expose the array reference to other code, the @SafeVarargs annotation can be applied to the method to suppress this warning. @SafeVarargs Syntactic Constraints To prevent subclasses from overriding a safe method with an unsafe implementation, the Java compiler restricts where @SafeVarargs can be applied. It is strictly limited to constructors and methods that cannot be overridden. Attempting to apply @SafeVarargs to a standard, non-final instance method results in a compilation error. Valid targets for @SafeVarargs include:
  • Constructors
  • static methods
  • final instance methods
  • private instance methods (supported since Java 9)
// Valid: Method cannot be overridden
@SafeVarargs
public final void processLists(List<String>... lists) { }

// Compilation Error: Method can be overridden
// @SafeVarargs
// public void processLists(List<String>... lists) { }
Master Java with Deep Grasping Methodology!Learn More