You're building a logging method. Sometimes you log one value, sometimes five. Instead of overloading for every count, varargs lets you accept any number of arguments with a single method definition.

Accept any number of arguments

Define a method that takes zero or more values.

BasicVarargs.java
public class BasicVarargs {
    public static void main(String[] args) {
        System.out.println("=== Basic Varargs ===\n");

        // Call with different numbers of arguments
        printAll();                           // Zero args
        printAll("Hello");                    // One arg
        printAll("Alice", "Bob");             // Two args
        printAll("Red", "Green", "Blue");     // Three args

        System.out.println("\n=== Inside the Method ===");
        showDetails("a", "b", "c");

        // Typed varargs
        System.out.println("\n=== Integer Varargs ===");
        showNumbers(10, 20, 30, 40);
    }

    // Varargs method
    static void printAll(String... messages) {
        System.out.println("Called with " + messages.length + " argument(s):");
        for (String msg : messages) {
            System.out.println("  - " + msg);
        }
    }

    static void showDetails(String... items) {
        System.out.println("items.getClass(): " + items.getClass().getSimpleName());
        System.out.println("items.length: " + items.length);
        System.out.print("items contents: ");
        for (int i = 0; i < items.length; i++) {
            System.out.print(items[i]);
            if (i < items.length - 1) System.out.print(", ");
        }
        System.out.println();
    }

    // Integer varargs
    static void showNumbers(int... nums) {
        System.out.println("Received " + nums.length + " integers");
        int sum = 0;
        for (int n : nums) sum += n;
        System.out.println("Sum: " + sum);
    }
}

Use Type... name syntax. Inside the method, it's an array.

varargs Variable arguments: `void print(String... items)`. Received as array.

Sum any count of numbers

Calculate the sum of however many numbers are passed.

SumNumbers.java
public class SumNumbers {
    public static void main(String[] args) {
        System.out.println("=== Summing with Varargs ===\n");

        // Sum different counts of numbers
        int bonus = ;
        System.out.println("sum() = " + sum());
        System.out.println("sum(" + bonus + ") = " + sum(bonus));
        System.out.println("sum(1, 2, " + bonus + ") = " + sum(1, 2, bonus));
        System.out.println("sum(10, 20, 30, 40, " + bonus + ") = " + sum(10, 20, 30, 40, bonus));

        System.out.println("\n=== Finding Max ===");
        System.out.println("max(5) = " + max(5));
        System.out.println("max(3, 7, 2) = " + max(3, 7, 2));
        System.out.println("max(10, -5, 8, 20, 15) = " + max(10, -5, 8, 20, 15));

        // Extended stats
        System.out.println("\n=== Statistics ===");
        stats(1, 2, 3, 4, bonus);
        stats(10, 20, 30);
    }

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

    static int max(int first, int... rest) {
        // first guarantees at least one argument
        int maximum = first;
        for (int n : rest) {
            if (n > maximum) {
                maximum = n;
            }
        }
        return maximum;
    }

    // Stats helper
    static void stats(int... numbers) {
        if (numbers.length == 0) {
            System.out.println("No numbers provided");
            return;
        }
        int sum = 0, min = numbers[0], max = numbers[0];
        for (int n : numbers) {
            sum += n;
            if (n < min) min = n;
            if (n > max) max = n;
        }
        double avg = (double) sum / numbers.length;
        System.out.printf("Count: %d, Sum: %d, Avg: %.2f, Min: %d, Max: %d%n",
            numbers.length, sum, avg, min, max);
    }
}
public class SumNumbers {
    public static void main(String[] args) {
        System.out.println("=== Summing with Varargs ===\n");

        // Sum different counts of numbers
        int bonus = ;
        System.out.println("sum() = " + sum());
        System.out.println("sum(" + bonus + ") = " + sum(bonus));
        System.out.println("sum(1, 2, " + bonus + ") = " + sum(1, 2, bonus));
        System.out.println("sum(10, 20, 30, 40, " + bonus + ") = " + sum(10, 20, 30, 40, bonus));

        System.out.println("\n=== Finding Max ===");
        System.out.println("max(5) = " + max(5));
        System.out.println("max(3, 7, 2) = " + max(3, 7, 2));
        System.out.println("max(10, -5, 8, 20, 15) = " + max(10, -5, 8, 20, 15));

        // Extended stats
        System.out.println("\n=== Statistics ===");
        stats(1, 2, 3, 4, bonus);
        stats(10, 20, 30);
    }

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

    static int max(int first, int... rest) {
        // first guarantees at least one argument
        int maximum = first;
        for (int n : rest) {
            if (n > maximum) {
                maximum = n;
            }
        }
        return maximum;
    }

    // Stats helper
    static void stats(int... numbers) {
        if (numbers.length == 0) {
            System.out.println("No numbers provided");
            return;
        }
        int sum = 0, min = numbers[0], max = numbers[0];
        for (int n : numbers) {
            sum += n;
            if (n < min) min = n;
            if (n > max) max = n;
        }
        double avg = (double) sum / numbers.length;
        System.out.printf("Count: %d, Sum: %d, Avg: %.2f, Min: %d, Max: %d%n",
            numbers.length, sum, avg, min, max);
    }
}
public class SumNumbers {
    public static void main(String[] args) {
        System.out.println("=== Summing with Varargs ===\n");

        // Sum different counts of numbers
        int bonus = ;
        System.out.println("sum() = " + sum());
        System.out.println("sum(" + bonus + ") = " + sum(bonus));
        System.out.println("sum(1, 2, " + bonus + ") = " + sum(1, 2, bonus));
        System.out.println("sum(10, 20, 30, 40, " + bonus + ") = " + sum(10, 20, 30, 40, bonus));

        System.out.println("\n=== Finding Max ===");
        System.out.println("max(5) = " + max(5));
        System.out.println("max(3, 7, 2) = " + max(3, 7, 2));
        System.out.println("max(10, -5, 8, 20, 15) = " + max(10, -5, 8, 20, 15));

        // Extended stats
        System.out.println("\n=== Statistics ===");
        stats(1, 2, 3, 4, bonus);
        stats(10, 20, 30);
    }

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

    static int max(int first, int... rest) {
        // first guarantees at least one argument
        int maximum = first;
        for (int n : rest) {
            if (n > maximum) {
                maximum = n;
            }
        }
        return maximum;
    }

    // Stats helper
    static void stats(int... numbers) {
        if (numbers.length == 0) {
            System.out.println("No numbers provided");
            return;
        }
        int sum = 0, min = numbers[0], max = numbers[0];
        for (int n : numbers) {
            sum += n;
            if (n < min) min = n;
            if (n > max) max = n;
        }
        double avg = (double) sum / numbers.length;
        System.out.printf("Count: %d, Sum: %d, Avg: %.2f, Min: %d, Max: %d%n",
            numbers.length, sum, avg, min, max);
    }
}

Loop through the varargs array just like any array.

Combine regular and varargs parameters

Mix required parameters with varargs.

MixedParams.java
public class MixedParams {
    public static void main(String[] args) {
        System.out.println("=== Mixed Parameters with Varargs ===\n");

        // Required params + varargs
        log("INFO", "System started");
        log("DEBUG", "Loading config", "user.properties");
        log("ERROR", "Failed to connect", "timeout", "retry=3");

        System.out.println("\n=== Shopping Cart ===");
        printReceipt("Alice", 10.99, 24.50, 5.25);
        printReceipt("Bob", 99.99);

        System.out.println("\n=== Team Roster ===");
        printTeam("Engineering", "Alice", "Bob", "Charlie");
        printTeam("Marketing", "Diana", "Eve");
        printTeam("Executive");  // No members
    }

    // Level (required) + message (required) + details (varargs)
    static void log(String level, String message, String... details) {
        System.out.print("[" + level + "] " + message);
        if (details.length > 0) {
            System.out.print(" | ");
            System.out.print(String.join(", ", details));
        }
        System.out.println();
    }

    // Name + prices (at least one price makes sense)
    static void printReceipt(String customer, double... prices) {
        System.out.println("Receipt for: " + customer);
        double total = 0;
        for (int i = 0; i < prices.length; i++) {
            System.out.printf("  Item %d: $%.2f%n", i + 1, prices[i]);
            total += prices[i];
        }
        System.out.printf("  Total: $%.2f%n", total);
    }

    static void printTeam(String teamName, String... members) {
        System.out.print("Team " + teamName + ": ");
        if (members.length == 0) {
            System.out.println("(no members)");
        } else {
            System.out.println(String.join(", ", members));
        }
    }
}

Varargs must be the last parameter. Regular params come first.

Build printf-style formatting

Create a method that formats strings with variable placeholders.

PrintfStyle.java
public class PrintfStyle {
    public static void main(String[] args) {
        System.out.println("=== printf-Style Formatting ===\n");

        // Java's actual printf
        System.out.printf("Name: %s, Age: %d%n", "Alice", 30);
        System.out.printf("Price: $%.2f%n", 29.99);
        System.out.printf("%s scored %d points%n", "Bob", 150);

        System.out.println("\n=== Our Simple Format ===");

        // Our custom simpleFormat
        String msg1 = simpleFormat("Hello, {}!", "World");
        System.out.println(msg1);

        String msg2 = simpleFormat("{} + {} = {}", 10, 20, 30);
        System.out.println(msg2);

        String msg3 = simpleFormat("User {} logged in from {}", "alice", "192.168.1.1");
        System.out.println(msg3);

        System.out.println("\n=== Logging with Format ===");
        logf("INFO", "User {} completed task {}", "Bob", "cleanup");
        logf("ERROR", "Failed after {} retries", 3);
        logf("DEBUG", "Processing {} items from {}", 100, "queue-1");
    }

    // Custom format function like SLF4J
    static String simpleFormat(String template, Object... args) {
        String result = template;
        for (Object arg : args) {
            // Replace first {} with next argument
            result = result.replaceFirst("\\{\\}", String.valueOf(arg));
        }
        return result;
    }

    // Logging with formatting
    static void logf(String level, String template, Object... args) {
        String message = simpleFormat(template, args);
        System.out.println("[" + level + "] " + message);
    }
}

String.format() and printf() use varargs for their flexible APIs.

Pass an array to varargs

Arrays can be passed directly to varargs methods.

ArrayVsVarargs.java
import java.util.Arrays;

public class ArrayVsVarargs {
    public static void main(String[] args) {
        System.out.println("=== Arrays and Varargs ===\n");

        // Call with individual arguments (normal varargs)
        printItems("apple", "banana", "cherry");

        // Call with existing array
        String[] fruits = {"orange", "grape", "mango"};
        printItems(fruits);  // Array passed directly!

        System.out.println("\n=== Creating Arrays ===");

        // Traditional array creation
        int[] arr1 = new int[]{1, 2, 3};

        // Using varargs-based method
        int[] arr2 = createArray(4, 5, 6);

        System.out.println("arr1: " + Arrays.toString(arr1));
        System.out.println("arr2: " + Arrays.toString(arr2));

        System.out.println("\n=== Arrays.asList (varargs) ===");
        var list = Arrays.asList("x", "y", "z");
        System.out.println("List: " + list);

        // Also works with array
        String[] letters = {"a", "b", "c"};
        var list2 = Arrays.asList(letters);
        System.out.println("List from array: " + list2);
    }

    static void printItems(String... items) {
        System.out.println("Received " + items.length + " items:");
        for (String item : items) {
            System.out.println("  - " + item);
        }
    }

    // Return array from varargs
    static int[] createArray(int... values) {
        return values;  // values IS the array!
    }
}

Varargs and arrays are interchangeable at the call site.

Exercise: VarargsOverload.java

Explore overloading ambiguity with varargs