Java Tutorial
🔍

Java Variable Arguments (varargs)

Java Variable Arguments (varargs)

Before varargs existed in Java 5, writing a method that accepted a flexible number of arguments meant either creating multiple overloads for one, two, three, four arguments, or forcing the caller to pack everything into an array first. Both approaches were clumsy. Varargs solved this.

A varargs parameter lets a method accept any number of arguments of the same type — zero, one, five, or a hundred — without the caller needing to create an array or the developer needing to write multiple overloads. The JVM creates the array behind the scenes.

What Are varargs?

varargs (variable arguments) is a special parameter syntax that allows a method to accept zero or more arguments of the same type. It is declared using three dots (...) after the type.

1// This method accepts any number of int arguments 2public int sum(int... numbers) { ... } 3 4// All of these are valid calls: 5sum() // zero arguments 6sum(10) // one argument 7sum(10, 20) // two arguments 8sum(10, 20, 30, 40) // four arguments 9int[] arr = {1, 2, 3}; 10sum(arr) // passing an existing array

Inside the method, numbers is treated as a plain int[]. The JVM collects whatever arguments are passed into an array before calling the method.

What the JVM does:

  Caller writes:  sum(10, 20, 30)
                     |
                     v
  JVM creates:    int[] numbers = {10, 20, 30}
                     |
                     v
  Method receives: sum(int[] numbers)  — works like a normal array

Basic Syntax and Usage

1// File: VarargsBasics.java 2 3public class VarargsBasics { 4 5 // Accepts zero or more int values 6 public int sum(int... numbers) { 7 int total = 0; 8 for (int n : numbers) { 9 total += n; 10 } 11 return total; 12 } 13 14 // Accepts zero or more Strings 15 public void printAll(String... messages) { 16 System.out.println("Total messages: " + messages.length); 17 for (String msg : messages) { 18 System.out.println(" " + msg); 19 } 20 } 21 22 // varargs combined with regular parameters 23 // Regular parameter MUST come before the varargs parameter 24 public void log(String level, String... messages) { 25 for (String msg : messages) { 26 System.out.println("[" + level + "] " + msg); 27 } 28 } 29 30 public static void main(String[] args) { 31 32 VarargsBasics vb = new VarargsBasics(); 33 34 // sum — different number of arguments 35 System.out.println("sum() = " + vb.sum()); 36 System.out.println("sum(5) = " + vb.sum(5)); 37 System.out.println("sum(1,2,3) = " + vb.sum(1, 2, 3)); 38 System.out.println("sum(10,20,30,40)= " + vb.sum(10, 20, 30, 40)); 39 40 // Existing array also works directly 41 int[] marks = {85, 90, 78, 95, 88}; 42 System.out.println("sum(array) = " + vb.sum(marks)); 43 44 System.out.println(); 45 vb.printAll(); // zero arguments — messages.length is 0 46 System.out.println(); 47 vb.printAll("Server started", "Database connected"); 48 49 System.out.println(); 50 vb.log("INFO", "Server started", "Listening on port 8080"); 51 vb.log("ERROR", "Connection refused"); 52 } 53}
Output:
sum()           = 0
sum(5)          = 5
sum(1,2,3)      = 6
sum(10,20,30,40)= 100
sum(array)      = 436

Total messages: 0

Total messages: 2
  Server started
  Database connected

[INFO] Server started
[INFO] Listening on port 8080
[ERROR] Connection refused

When no arguments are passed, numbers.length is 0 and the loop body never executes — the method returns 0 cleanly. The caller never needs to create an array or check whether to pass null.

varargs Rules — What You Must Know

Rule 1 — Only ONE varargs parameter per method.

  VALID:   void method(int... nums)
  VALID:   void method(String s, int... nums)
  INVALID: void method(int... nums, String... strs)   ← compile error

Rule 2 — varargs must be the LAST parameter.

  VALID:   void log(String level, String... messages)
  INVALID: void log(String... messages, String level) ← compile error

Rule 3 — The varargs parameter is a regular array inside the method.

  public void show(int... nums) {
      int[] arr = nums;   // valid — nums IS an int[]
      nums.length;        // valid
      nums[0];            // valid — but check length first!
  }

Rule 4 — An existing array can be passed directly.

  int[] values = {1, 2, 3};
  sum(values); // valid — array passed as varargs

Rule 5 — null can be passed but causes NullPointerException when iterated.

  sum(null); // compiles, but nums is null inside — NPE if you access nums.length

varargs vs Array Parameter — Comparison Table

Aspectint... numbers (varargs)int[] numbers (array)
Caller syntaxmethod(1, 2, 3) — no array neededmethod(new int[]{1,2,3}) — array required
Zero argumentsmethod() — validmethod(new int[]{}) or method(null)
Passing existing arraymethod(arr) — works directlymethod(arr) — works directly
Inside the methodTreated as a regular arrayTreated as a regular array
Position in parameter listMust be lastAny position
Multiple varargs in one methodNot allowed — only oneMultiple array params allowed
OverloadingCompiler prefers exact match over varargsNormal overload resolution
JVMCreates array from supplied argumentsArray passed directly — no creation
Readability at call siteClean — sum(1, 2, 3)Verbose — sum(new int[]{1, 2, 3})
When to useWhen the number of arguments genuinely variesWhen you always have a pre-existing array

varargs and Overloading — How the Compiler Chooses

The compiler treats varargs as a last-resort match. If an exact-match overload exists, it is always preferred over the varargs version.

1// File: VarargsOverloadDemo.java 2 3public class VarargsOverloadDemo { 4 5 // Exact match — two ints 6 public static void display(int a, int b) { 7 System.out.println("Two-int overload: " + a + ", " + b); 8 } 9 10 // Exact match — one int 11 public static void display(int a) { 12 System.out.println("One-int overload: " + a); 13 } 14 15 // varargs — last resort 16 public static void display(int... nums) { 17 System.out.println("varargs overload, count=" + nums.length); 18 for (int n : nums) System.out.print(n + " "); 19 if (nums.length > 0) System.out.println(); 20 } 21 22 public static void main(String[] args) { 23 24 display(5); // exact match — one-int overload 25 display(5, 10); // exact match — two-int overload 26 display(5, 10, 15); // no exact match — varargs 27 display(); // no exact match — varargs with zero elements 28 display(1, 2, 3, 4); // no exact match — varargs 29 } 30}
Output:
One-int overload: 5
Two-int overload: 5, 10
varargs overload, count=3
5 10 15 
varargs overload, count=0
varargs overload, count=4
1 2 3 4 

display(5) and display(5, 10) both have exact-match overloads — they never touch the varargs version. Only calls with three or more arguments, or zero arguments, fall through to the varargs overload.

varargs With Different Types

Varargs works with any type — including String, custom classes, and Object for mixed types.

1// File: VarargsTypesDemo.java 2 3public class VarargsTypesDemo { 4 5 // String varargs 6 public static String joinWith(String separator, String... parts) { 7 if (parts.length == 0) return ""; 8 StringBuilder sb = new StringBuilder(parts[0]); 9 for (int i = 1; i < parts.length; i++) { 10 sb.append(separator).append(parts[i]); 11 } 12 return sb.toString(); 13 } 14 15 // double varargs — calculates average 16 public static double average(double... values) { 17 if (values.length == 0) return 0.0; 18 double sum = 0; 19 for (double v : values) sum += v; 20 return sum / values.length; 21 } 22 23 // Object varargs — accepts anything 24 public static void printDetails(String label, Object... attributes) { 25 System.out.print(label + ": "); 26 for (int i = 0; i < attributes.length; i++) { 27 System.out.print(attributes[i]); 28 if (i < attributes.length - 1) System.out.print(" | "); 29 } 30 System.out.println(); 31 } 32 33 public static void main(String[] args) { 34 35 // String varargs 36 System.out.println(joinWith(", ", "Priya", "Rohan", "Sneha", "Karan")); 37 System.out.println(joinWith(" / ", "Mumbai", "Delhi", "Bengaluru")); 38 System.out.println(joinWith("-", "2024", "01", "15")); 39 40 System.out.println(); 41 42 // double varargs 43 System.out.printf("Avg marks : %.2f%n", average(85.0, 90.0, 78.0, 95.0)); 44 System.out.printf("Avg single : %.2f%n", average(100.0)); 45 System.out.printf("Avg empty : %.2f%n", average()); 46 47 System.out.println(); 48 49 // Object varargs — mix of types 50 printDetails("Employee", "EMP-042", "Priya Mehta", "Engineering", 85000); 51 printDetails("Product", "SKU-101", "Laptop", "Electronics", 45999.0, true); 52 } 53}
Output:
Priya, Rohan, Sneha, Karan
Mumbai / Delhi / Bengaluru
2024-01-15

Avg marks  : 87.00
Avg single : 100.00
Avg empty  : 0.00

Employee: EMP-042 | Priya Mehta | Engineering | 85000
Product: SKU-101 | Laptop | Electronics | 45999.0 | true

Object... attributes accepts any mix of types — the JVM boxes primitives automatically. This is exactly how String.format, printf, and logging frameworks like Log4j accept format arguments.

Real-World Example 1 — Report Builder for a School Management System

The Business Problem

A school management system used in institutions like CBSE schools or coaching centres generates student progress reports. A report line can carry different amounts of data depending on which subjects the student appeared for — some students have five subjects, others have eight. Rather than creating separate methods for each possible count, a varargs-based report builder handles all cases cleanly.

1// File: SubjectScore.java 2 3public class SubjectScore { 4 5 private final String subject; 6 private final int marks; 7 private final int maxMarks; 8 9 public SubjectScore(String subject, int marks, int maxMarks) { 10 this.subject = subject; 11 this.marks = marks; 12 this.maxMarks = maxMarks; 13 } 14 15 public String getSubject() { return subject; } 16 public int getMarks() { return marks; } 17 public int getMaxMarks() { return maxMarks; } 18 public double getPercent() { return (marks * 100.0) / maxMarks; } 19 20 public String getGrade() { 21 double pct = getPercent(); 22 if (pct >= 90) return "A+"; 23 if (pct >= 75) return "A"; 24 if (pct >= 60) return "B"; 25 if (pct >= 45) return "C"; 26 return "D"; 27 } 28 29 @Override 30 public String toString() { 31 return String.format("%-20s %3d/%3d %-3s (%.1f%%)", 32 subject, marks, maxMarks, getGrade(), getPercent()); 33 } 34}
1// File: ReportBuilder.java 2 3public class ReportBuilder { 4 5 private static final String DIVIDER = "─".repeat(52); 6 7 // varargs — handles any number of subjects cleanly 8 public void generateReport(String studentName, 9 String rollNumber, 10 String className, 11 SubjectScore... scores) { 12 13 System.out.println(DIVIDER); 14 System.out.println(" STUDENT PROGRESS REPORT"); 15 System.out.println(DIVIDER); 16 System.out.printf(" Name : %s%n", studentName); 17 System.out.printf(" Roll No : %s%n", rollNumber); 18 System.out.printf(" Class : %s%n", className); 19 System.out.println(DIVIDER); 20 System.out.printf(" %-20s %7s %-3s %s%n", 21 "Subject", "Marks", "Grade", "Percent"); 22 System.out.println(DIVIDER); 23 24 if (scores.length == 0) { 25 System.out.println(" No scores recorded."); 26 } else { 27 int totalMarks = 0; 28 int totalMaxMarks = 0; 29 30 for (SubjectScore score : scores) { 31 System.out.println(" " + score); 32 totalMarks += score.getMarks(); 33 totalMaxMarks += score.getMaxMarks(); 34 } 35 36 double overallPct = (totalMarks * 100.0) / totalMaxMarks; 37 System.out.println(DIVIDER); 38 System.out.printf(" %-20s %3d/%3d (%.1f%%)%n", 39 "TOTAL", totalMarks, totalMaxMarks, overallPct); 40 System.out.printf(" Overall Grade: %s%n", 41 overallPct >= 75 ? "DISTINCTION" : 42 overallPct >= 60 ? "FIRST CLASS" : 43 overallPct >= 45 ? "PASS" : "FAIL"); 44 } 45 System.out.println(DIVIDER); 46 } 47}
1// File: SchoolReportDemo.java 2 3public class SchoolReportDemo { 4 5 public static void main(String[] args) { 6 7 ReportBuilder builder = new ReportBuilder(); 8 9 // Student 1 — 5 subjects 10 builder.generateReport( 11 "Priya Sharma", "R-2024-042", "Class X - A", 12 new SubjectScore("Mathematics", 92, 100), 13 new SubjectScore("Science", 88, 100), 14 new SubjectScore("English", 79, 100), 15 new SubjectScore("Hindi", 83, 100), 16 new SubjectScore("Social Studies", 76, 100) 17 ); 18 19 System.out.println(); 20 21 // Student 2 — 8 subjects (PCM + extras) 22 builder.generateReport( 23 "Rohan Mehta", "R-2024-078", "Class XII - Science", 24 new SubjectScore("Physics", 75, 100), 25 new SubjectScore("Chemistry", 68, 100), 26 new SubjectScore("Mathematics", 82, 100), 27 new SubjectScore("English", 71, 100), 28 new SubjectScore("Computer Science", 94, 100), 29 new SubjectScore("Physical Education", 88, 100) 30 ); 31 32 System.out.println(); 33 34 // Student 3 — no scores yet (varargs allows zero) 35 builder.generateReport("Sneha Rao", "R-2024-015", "Class IX - B"); 36 } 37}
Output:
────────────────────────────────────────────────────
  STUDENT PROGRESS REPORT
────────────────────────────────────────────────────
  Name    : Priya Sharma
  Roll No : R-2024-042
  Class   : Class X - A
────────────────────────────────────────────────────
  Subject              Marks  Grade Percent
────────────────────────────────────────────────────
  Mathematics            92/100  A+  (92.0%)
  Science                88/100  A   (88.0%)
  English                79/100  A   (79.0%)
  Hindi                  83/100  A   (83.0%)
  Social Studies         76/100  A   (76.0%)
────────────────────────────────────────────────────
  TOTAL                418/500       (83.6%)
  Overall Grade: DISTINCTION
────────────────────────────────────────────────────

────────────────────────────────────────────────────
  STUDENT PROGRESS REPORT
────────────────────────────────────────────────────
  Name    : Rohan Mehta
  Roll No : R-2024-078
  Class   : Class XII - Science
────────────────────────────────────────────────────
  Subject              Marks  Grade Percent
────────────────────────────────────────────────────
  Physics                75/100  A   (75.0%)
  Chemistry              68/100  B   (68.0%)
  Mathematics            82/100  A   (82.0%)
  English                71/100  B   (71.0%)
  Computer Science       94/100  A+  (94.0%)
  Physical Education     88/100  A   (88.0%)
────────────────────────────────────────────────────
  TOTAL                478/600       (79.7%)
  Overall Grade: DISTINCTION
────────────────────────────────────────────────────

────────────────────────────────────────────────────
  STUDENT PROGRESS REPORT
────────────────────────────────────────────────────
  Name    : Sneha Rao
  Roll No : R-2024-015
  Class   : Class IX - B
────────────────────────────────────────────────────
  Subject              Marks  Grade Percent
────────────────────────────────────────────────────
  No scores recorded.
────────────────────────────────────────────────────

One generateReport method handles five subjects, six subjects, and zero subjects without any changes. Without varargs, you would need separate overloads — or force the caller to always build a SubjectScore[] manually before calling the method.

Real-World Example 2 — Order Summary Builder for an E-Commerce App

The Business Problem

A food ordering app like Zomato or Swiggy displays an order summary before checkout. A customer might order one item or ten items. The summary builder must handle any count, calculate the total, and apply delivery charges — all through one clean method call that reads naturally for any number of items.

1// File: FoodItem.java 2 3public class FoodItem { 4 5 private final String name; 6 private final double price; 7 private final int quantity; 8 9 public FoodItem(String name, double price, int quantity) { 10 this.name = name; 11 this.price = price; 12 this.quantity = quantity; 13 } 14 15 public String getName() { return name; } 16 public double getPrice() { return price; } 17 public int getQuantity() { return quantity; } 18 public double getLineTotal(){ return price * quantity; } 19 20 @Override 21 public String toString() { 22 return String.format(" %-25s x%d Rs.%7.2f", name, quantity, getLineTotal()); 23 } 24}
1// File: OrderSummaryService.java 2 3public class OrderSummaryService { 4 5 private static final double DELIVERY_FEE = 30.0; 6 private static final double FREE_DELIVERY_ABOVE = 299.0; 7 private static final double GST_RATE = 0.05; 8 9 // varargs — any number of food items 10 public void printOrderSummary(String customerName, 11 String restaurantName, 12 FoodItem... items) { 13 14 System.out.println("╔══════════════════════════════════════════╗"); 15 System.out.println("║ ORDER SUMMARY ║"); 16 System.out.println("╠══════════════════════════════════════════╣"); 17 System.out.printf("║ Customer : %-27s║%n", customerName); 18 System.out.printf("║ Restaurant : %-27s║%n", restaurantName); 19 System.out.println("╠══════════════════════════════════════════╣"); 20 21 if (items.length == 0) { 22 System.out.println("║ No items in order. ║"); 23 System.out.println("╚══════════════════════════════════════════╝"); 24 return; 25 } 26 27 double subtotal = 0; 28 for (FoodItem item : items) { 29 System.out.println("║" + item + "║"); 30 subtotal += item.getLineTotal(); 31 } 32 33 double gst = subtotal * GST_RATE; 34 double delivery = subtotal >= FREE_DELIVERY_ABOVE ? 0.0 : DELIVERY_FEE; 35 double total = subtotal + gst + delivery; 36 37 System.out.println("╠══════════════════════════════════════════╣"); 38 System.out.printf("║ %-25s Rs.%7.2f║%n", "Subtotal", subtotal); 39 System.out.printf("║ %-25s Rs.%7.2f║%n", "GST (5%)", gst); 40 System.out.printf("║ %-25s Rs.%7.2f║%n", 41 delivery == 0 ? "Delivery (FREE!)" : "Delivery", delivery); 42 System.out.println("╠══════════════════════════════════════════╣"); 43 System.out.printf("║ %-25s Rs.%7.2f║%n", "TOTAL", total); 44 System.out.println("╚══════════════════════════════════════════╝"); 45 } 46 47 // varargs overload — calculates total without printing 48 public double calculateTotal(FoodItem... items) { 49 double subtotal = 0; 50 for (FoodItem item : items) subtotal += item.getLineTotal(); 51 double delivery = subtotal >= FREE_DELIVERY_ABOVE ? 0.0 : DELIVERY_FEE; 52 return subtotal + (subtotal * GST_RATE) + delivery; 53 } 54}
1// File: ZomatoOrderDemo.java 2 3public class ZomatoOrderDemo { 4 5 public static void main(String[] args) { 6 7 OrderSummaryService service = new OrderSummaryService(); 8 9 // Order 1 — single item (qualifies for free delivery) 10 System.out.println("=== Order 1 ===\n"); 11 service.printOrderSummary( 12 "Priya Mehta", "Biryani House", 13 new FoodItem("Chicken Biryani (Full)", 349.0, 1) 14 ); 15 16 System.out.println(); 17 18 // Order 2 — multiple items 19 System.out.println("=== Order 2 ===\n"); 20 service.printOrderSummary( 21 "Rohan Sharma", "Pizza Palace", 22 new FoodItem("Margherita Pizza", 199.0, 1), 23 new FoodItem("Garlic Bread", 79.0, 2), 24 new FoodItem("Pasta Arrabiata", 149.0, 1), 25 new FoodItem("Cold Coffee", 69.0, 2) 26 ); 27 28 System.out.println(); 29 30 // Order 3 — large family order 31 System.out.println("=== Order 3 ===\n"); 32 service.printOrderSummary( 33 "Sneha Kapoor", "South Indian Corner", 34 new FoodItem("Masala Dosa", 89.0, 3), 35 new FoodItem("Idli Sambar (4 pcs)", 69.0, 2), 36 new FoodItem("Filter Coffee", 35.0, 4), 37 new FoodItem("Medu Vada", 49.0, 2), 38 new FoodItem("Pongal", 79.0, 1) 39 ); 40 41 // Quick total without printing 42 double quickTotal = service.calculateTotal( 43 new FoodItem("Veg Wrap", 129.0, 2), 44 new FoodItem("Smoothie", 99.0, 1) 45 ); 46 System.out.printf("%nQuick total for 3 items: Rs.%.2f%n", quickTotal); 47 } 48}
Output:
=== Order 1 ===

╔══════════════════════════════════════════╗
║         ORDER SUMMARY                   ║
╠══════════════════════════════════════════╣
║  Customer   : Priya Mehta               ║
║  Restaurant : Biryani House             ║
╠══════════════════════════════════════════╣
║  Chicken Biryani (Full)   x1  Rs. 349.00║
╠══════════════════════════════════════════╣
║  Subtotal                       Rs.349.00║
║  GST (5%)                       Rs. 17.45║
║  Delivery (FREE!)               Rs.  0.00║
╠══════════════════════════════════════════╣
║  TOTAL                          Rs.366.45║
╚══════════════════════════════════════════╝

=== Order 2 ===

╔══════════════════════════════════════════╗
║         ORDER SUMMARY                   ║
╠══════════════════════════════════════════╣
║  Customer   : Rohan Sharma              ║
║  Restaurant : Pizza Palace              ║
╠══════════════════════════════════════════╣
║  Margherita Pizza         x1  Rs. 199.00║
║  Garlic Bread             x2  Rs. 158.00║
║  Pasta Arrabiata          x1  Rs. 149.00║
║  Cold Coffee              x2  Rs. 138.00║
╠══════════════════════════════════════════╣
║  Subtotal                       Rs.644.00║
║  GST (5%)                       Rs. 32.20║
║  Delivery (FREE!)               Rs.  0.00║
╠══════════════════════════════════════════╣
║  TOTAL                          Rs.676.20║
╚══════════════════════════════════════════╝

Quick total for 3 items: Rs.397.35

The same printOrderSummary method handles one item, four items, five items, and zero items. Without varargs, Zomato's backend would need printOrderSummary(FoodItem item1), printOrderSummary(FoodItem i1, FoodItem i2), and so on — or force every caller to build a FoodItem[]. Varargs makes the call site read naturally, just like placing an order in the app.

Best Practices

Always handle the zero-argument case explicitly. When scores.length == 0 is valid input, handle it — print "no items", return 0, return an empty list. Do not assume the varargs array always has elements. Do not access arr[0] without checking arr.length > 0 first.

Use varargs when the argument count genuinely varies at the call site. If every caller always passes exactly two or three values, write two or three explicit parameters — the call site is clearer and mistakes are caught at compile time. Varargs is for genuine variability, not for avoiding the effort of typing parameter names.

Never store the varargs array reference outside the method. The JVM creates a new array for each call. Storing it and relying on it after the method returns is fragile — the caller might not expect the array to be held by anything.

Prefer explicit parameters for the first one or two required arguments. Write log(String level, String... messages) rather than log(String... args) when level is always required. The method signature communicates what is mandatory and what is optional, and the compiler enforces the mandatory part.

Common Mistakes

Mistake 1 — Accessing varargs Array Without Length Check

1public static double firstValue(double... values) { 2 return values[0]; // ArrayIndexOutOfBoundsException if called with no arguments 3} 4 5firstValue(); // caller passes nothing — values is empty — crash 6firstValue(10.0); // works fine 7 8// Fix — check length first 9public static double firstValue(double... values) { 10 if (values.length == 0) return 0.0; 11 return values[0]; 12}

Mistake 2 — Passing null Causes NullPointerException

1public static void printAll(String... messages) { 2 for (String msg : messages) { // NullPointerException here 3 System.out.println(msg); 4 } 5} 6 7printAll(null); // null is assigned to messages itself — not a null element inside 8// messages == null — iterating it with for-each throws NullPointerException
Exception in thread "main" java.lang.NullPointerException

When null is passed to a varargs method, Java interprets it as setting the entire array to null — not as an array containing one null element. Guard against it explicitly: if (messages == null) return; or use Objects.requireNonNull.

Mistake 3 — Ambiguous Overload With varargs

1public static void show(int... nums) { System.out.println("int varargs"); } 2public static void show(Integer... nums) { System.out.println("Integer varargs"); } 3 4show(1, 2, 3); // Compile error — ambiguous: 5 // 1, 2, 3 could match int... or Integer... (autoboxing)
Compile error: reference to show is ambiguous

Defining two varargs overloads where one is the autoboxed version of the other creates an ambiguity the compiler cannot resolve. Avoid having both int... and Integer... overloads for the same method name.

Mistake 4 — Putting varargs Before Other Parameters

1// Compile error — varargs must be the last parameter 2public static void register(String... names, String city) { } // error 3 4// Fix 5public static void register(String city, String... names) { } // correct
Compile error: varargs parameter must be the last parameter

Interview Questions

Q1. What are varargs in Java and how do they work internally?

varargs (variable arguments) allow a method to accept any number of arguments of the same type using the ... syntax. The JVM collects the supplied arguments into an array before calling the method — inside the method, the varargs parameter behaves as a regular array. A method can have at most one varargs parameter and it must be the last parameter in the list. Callers can pass individual values, an existing array, or nothing at all.

Q2. What are the rules for using varargs in Java?

A method can have only one varargs parameter. The varargs parameter must be the last parameter in the method signature — placing it before any other parameter causes a compile error. Inside the method, the varargs parameter is a regular array and can be iterated, passed to other methods, or checked with .length. An existing array can be passed directly as a varargs argument. When null is passed, the array reference itself is null — not an array containing null.

Q3. What is the difference between varargs and an array parameter?

A varargs parameter allows the caller to pass individual values directly — method(1, 2, 3) — while an array parameter forces the caller to construct an array first — method(new int[]{1, 2, 3}). Inside the method, both are treated identically as arrays. The key practical difference is call-site readability: varargs reads naturally for variable-count inputs, while an array parameter is better when the caller always has a pre-built collection.

Q4. How does the compiler resolve overloads when a varargs method and a fixed-parameter method both match?

The compiler applies a resolution order: exact match first, then widening, then autoboxing, and varargs last. If a fixed-parameter method matches the argument types exactly, it is always preferred over the varargs version. Varargs is the last resort — used only when no fixed-parameter method matches. This is why display(5, 10) calls the display(int, int) overload rather than display(int... nums) when both exist.

Q5. What happens when you pass null to a varargs method?

Java interprets null passed to a varargs parameter as setting the entire array reference to null, not as an array containing a single null element. Iterating over the parameter with a for-each loop then throws NullPointerException because the array itself is null. To handle this safely, check if (parameter == null) return; at the top of the method, or use Objects.requireNonNull.

Q6. Where does Java use varargs in its own standard library?

The most widely used varargs in the standard library are System.out.printf(String format, Object... args) and String.format(String format, Object... args) — which accept format strings and any number of values. Arrays.asList(T... elements) creates a list from any number of elements. Collections.addAll(Collection c, T... elements) adds multiple elements to a collection. Logging frameworks like SLF4J and Log4j use log.info(String message, Object... args) for parameterised logging.

FAQs

Can varargs be used with generics?

Yes — <T> with T... is valid. public static <T> List<T> listOf(T... elements) is a generic varargs method. However, mixing generics with varargs generates an unchecked warning — "Possible heap pollution via varargs parameter" — because the JVM cannot fully verify the type of the array at runtime due to type erasure. The @SafeVarargs annotation suppresses this warning when the developer is certain no heap pollution occurs.

Is the array created for varargs a new array every time?

Yes. The JVM creates a new array for each varargs call. This means a varargs method called millions of times in a tight loop creates millions of short-lived arrays, which can increase GC pressure. In performance-critical code where the argument count is always fixed, explicit parameters avoid this overhead.

Can you use varargs with constructors?

Yes. Constructors follow the same rules as methods. public Team(String teamName, String... members) is a valid varargs constructor. It is called with new Team("Dev", "Priya", "Rohan", "Sneha") — the JVM packs the member names into a String[].

What is @SafeVarargs and when do you use it?

@SafeVarargs is an annotation on a method with a generic varargs parameter — <T>. It suppresses the "unchecked or unsafe operations" warning the compiler generates for generic varargs. You add it when you are certain the method does not perform unsafe operations on the varargs array — it does not store the array into a variable of a different generic type. Without it, the compiler warns on every call to the method.

Can printf be called with zero format arguments?

Yes — System.out.printf("No placeholders here\n") is valid. The varargs part receives an empty Object[]. The method simply prints the format string with no substitutions. This is the same behaviour as calling any other varargs method with no variable arguments.

Summary

varargs removes the friction of working with a variable number of same-type arguments. The three dots ... tell the compiler to collect whatever is passed into an array — and the calling code reads naturally without array construction boilerplate. The JVM handles all the packaging; the method handles the logic.

The rules are few and memorable: one varargs per method, always last, treated as an array inside, last resort in overload resolution. The gotchas are equally few: check .length before indexing, guard against null, avoid ambiguous autoboxed varargs overloads.

In production code, varargs appears in every logging call, every format string, every builder or collector that accepts a batch of items. Every time a fresher writes System.out.printf("Name: %s, Age: %d", name, age), they are using varargs. Understanding what happens behind that call — array creation, overload resolution, null handling — is exactly what interviewers probe.

What to Read Next