Varargs (número variable de argumentos)

Intermedio
Java
Java
Actualizado: 18/04/2026

El problema: número variable de argumentos

Antes de Java 5, si querías escribir un método que aceptase un número variable de argumentos tenías que sobrecargar el método muchas veces o recibir un array:

// Antes de varargs: muchas sobrecargas
public static int max(int a, int b) { ... }
public static int max(int a, int b, int c) { ... }
public static int max(int a, int b, int c, int d) { ... }

// O recibiendo array (incómodo de llamar)
public static int max(int[] numeros) { ... }
// Uso: max(new int[]{1, 2, 3});

Desde Java 5, los varargs resuelven esto con una sintaxis elegante.

Sintaxis

Un parámetro varargs se declara con tipo... seguido del nombre. Debe ser el último parámetro del método:

public static int max(int... numeros) {
    int mayor = Integer.MIN_VALUE;
    for (int n : numeros) {
        if (n > mayor) mayor = n;
    }
    return mayor;
}

Y se llama con cualquier número de argumentos:

max(1, 2, 3);
max(10, 20, 30, 40, 50);
max(); // sin argumentos: numeros es un array vacío

Internamente es un array

Dentro del método, el parámetro varargs es un array normal del tipo declarado:

public static void info(String... palabras) {
    System.out.println("Recibidas " + palabras.length + " palabras:");
    for (int i = 0; i < palabras.length; i++) {
        System.out.println(i + ": " + palabras[i]);
    }
}

Puedes iterarlo con for-each, usar índices y preguntar por length. Es exactamente un String[].

Combinar con parámetros obligatorios

Los parámetros obligatorios van antes del varargs:

public static String unir(String separador, Object... valores) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < valores.length; i++) {
        if (i > 0) sb.append(separador);
        sb.append(valores[i]);
    }
    return sb.toString();
}

// Uso
unir(", ", "Ana", "Bob", "Carmen"); // "Ana, Bob, Carmen"
unir(" | ", 1, 2, 3); // "1 | 2 | 3"

Solo puede haber un varargs por método y debe ser el último parámetro. Esto es ilegal:

// ERROR: varargs no puede ir antes de otro parámetro
public static void x(int... nums, String nombre) { }

Pasar un array a un varargs

Si ya tienes un array, puedes pasarlo directamente:

int[] datos = {5, 2, 8, 1, 9};
int mayor = max(datos); // válido

Para pasar una colección, convierte primero:

List<String> nombres = List.of("Ana", "Bob");
String resultado = unir(", ", nombres.toArray());

Ejemplos en la API estándar

El JDK usa varargs constantemente:

// String.format
String.format("Nombre: %s, edad: %d", "Ana", 30);

// List.of, Set.of, Map.of (Java 9+)
List<Integer> lista = List.of(1, 2, 3, 4, 5);
Set<String> set = Set.of("a", "b", "c");

// Arrays.asList
List<Integer> otros = Arrays.asList(10, 20, 30);

// Collections.addAll
Collections.addAll(lista, 6, 7, 8);

// Stream.of
Stream<String> s = Stream.of("x", "y", "z");

// Path.of (NIO)
Path p = Path.of("home", "user", "docs");

Sobrecarga y ambigüedades

La sobrecarga con varargs puede generar resolución ambigua. Java prefiere siempre la versión más específica:

public static void log(String mensaje) { System.out.println("string: " + mensaje); }
public static void log(String... mensajes) { System.out.println(mensajes.length + " strings"); }

log("uno"); // llama a log(String): más específica
log("uno", "dos"); // llama a log(String...)
log(); // llama a log(String...) con array vacío

Cuando haya duda, el compilador elige la no-varargs si cuadra; si no, la varargs.

Varargs de tipos genéricos: advertencia @SafeVarargs

Los varargs de tipos genéricos (List<String>...) generan un warning porque el array interno no preserva el tipo genérico (type erasure). Si tu método es seguro, añade @SafeVarargs:

@SafeVarargs
public static <T> List<T> unirListas(List<T>... listas) {
    List<T> resultado = new ArrayList<>();
    for (List<T> l : listas) {
        resultado.addAll(l);
    }
    return resultado;
}

@SafeVarargs solo puede aplicarse a métodos static, final o constructores (donde no puede haber polimorfismo que rompa la seguridad).

Buenas prácticas

  • Usa varargs cuando el número de argumentos típico sea pequeño y variable (0-5). Para listas de tamaño arbitrario, prefiere recibir List<T> o Collection<T>.
  • No abuses de varargs para aceptar "cualquier cosa" con Object...: pierdes seguridad de tipos.
  • Cuidado al sobrecargar métodos con varargs; puede haber conflictos con autoboxing o covariance.
  • Declara colecciones inmutables con List.of(...) / Set.of(...) / Map.of(...): usan varargs por debajo.

Los varargs son una herramienta de conveniencia para APIs limpias; bien usados mejoran legibilidad, mal usados esconden costes de creación de arrays.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Java es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Java

Explora más contenido relacionado con Java y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Declarar métodos con la sintaxis tipo... nombre. Comprender que varargs internamente es un array. Combinar parámetros obligatorios con varargs. Llamar a varargs con argumentos, array o colección (toArray()). Evitar ambigüedades al sobrecargar métodos con varargs. Conocer ejemplos reales: String.format, List.of, Arrays.asList.