W3docs

Java Varargs (Argumentos de longitud variable)

Define métodos Java que aceptan cualquier número de argumentos con varargs (Type... name). Aprende las reglas, convenciones de llamada, sobrecarga y errores comunes.

Un parámetro varargs (abreviatura de variable-length arguments) permite que un método acepte cualquier número de argumentos — cero, uno, diez, cien — del mismo tipo, sin obligar al llamador a agruparlos en un array primero. Se escribe el último parámetro como Type... name, y dentro del método name es un array ordinario de ese tipo.

Has usado métodos varargs durante años. String.format("%s + %s = %s", a, b, c) acepta tantos valores de sustitución como necesite la cadena de formato. List.of(1, 2, 3, 4, 5) acepta una lista arbitraria de elementos. Ambos dependen de varargs.

Declarar un parámetro varargs

La sintaxis son tres puntos entre el tipo del elemento y el nombre del parámetro:

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

Los llamadores pasan cualquier número de argumentos int:

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

Dentro del método, numbers es un int[]. El compilador agrupa los argumentos sueltos en un array en el lugar de la llamada.

Varargs no es más que un array

El cuerpo trata el parámetro varargs exactamente como un array — .length, indexación, for-each, todo:

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("-");                            // ""

Como el parámetro es un array, también puedes pasar directamente un array literal:

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

El compilador acepta cualquiera de las dos formas.

Las reglas

La sintaxis trae consigo algunas restricciones:

  • Un método puede tener como máximo un parámetro varargs. Dos serían ambiguos.
  • Debe ser el último parámetro. De lo contrario, el compilador no podría saber dónde terminan los argumentos variables y comienza el siguiente parámetro.
  • Los demás parámetros van primero. Los parámetros fijos al principio, varargs al final.
// 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

Llamar a métodos varargs

Puedes pasar:

  1. Valores sueltosf(1, 2, 3).
  2. Un array del tipo adecuadof(new int[]{1, 2, 3}).
  3. Nada en absolutof(). El método recibe un array de longitud 0, no 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}

Un argumento null es un caso complicado: sum(null) compila, trata null como el propio array, y el bucle lanza una NullPointerException. La mayoría de los métodos varargs no esperan null.

Varargs y sobrecarga

Cuando sobrecargas un método, las versiones varargs se comprueban al final. Se preferirá una sobrecarga sin varargs (aridad fija) que coincida:

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"

Esto es correcto — varargs es el recurso alternativo, y solo se usa cuando no encaja nada más específico.

Un error común: Object...

El varargs de Object acepta cualquier cosa, incluido un 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;@..."

El compilador elige la interpretación que produce una llamada válida. Con Object..., ambas interpretaciones funcionan, y las reglas se inclinan hacia "tratar el array como el array varargs." Si quieres el array como un único elemento, haz un cast: log((Object) names).

Cuándo usar (y cuándo no) varargs

Varargs es una comodidad en el lugar de la llamada, no una abstracción gratuita. Cada llamada que pasa valores sueltos asigna un array nuevo entre bastidores. Para métodos llamados en bucles ajustados en una ruta crítica, esa asignación puede acumularse — razón por la cual la biblioteca estándar a veces incluye sobrecargas de aridad fija junto a la versión varargs. List.of es el ejemplo clásico: tiene sobrecargas dedicadas para of(), of(e1), of(e1, e2) hasta diez elementos, y solo recurre a un varargs of(E... elements) a partir de ahí.

Para el código cotidiano el coste es insignificante, y la claridad es lo que importa. Usa varargs cuando:

  • el número de argumentos varía genuinamente (formateo, logging, construcción de colecciones);
  • obligar al llamador a escribir new Type[]{...} sería ruido innecesario.

Prefiere un array plano o un parámetro List cuando el llamador normalmente ya tiene una colección en mano, o cuando quieres que "pasar muchos valores" sea el caso explícito y esperado.

Un ejemplo completo

java— editable, runs on the server

Qué viene a continuación

Ahora puedes escribir métodos con toda la variedad de formas de parámetros que ofrece Java — fijos, sobrecargados, recursivos y varargs. El capítulo final de la parte de métodos vuelve al único método que tiene todo programa: el método main — cuyo String[] args puede escribirse igualmente como String... args — y lo que su firma le dice realmente a la JVM.

Práctica

Práctica
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?