Varargs: Argumentos Variables en Java

Intermedio

Algunas veces querrá crear un método que tome una cantidad variable de argumentos, según su uso preciso. Por ejemplo, un método que abre una conexión a Internet puede tomar un nombre de usuario, contraseña, nombre de archivo, protocolo, etc., pero proporcionará los valores predeterminados si no se proporciona parte de esta información.

En esta situación, sería conveniente pasar solo los argumentos a los que no se aplicaron los valores predeterminados. Crear dicho método implica que debe haber alguna forma de crear una lista de argumentos que sea de longitud variable, en lugar de fija.

1. Argumentos de longitud variable

En el pasado, los métodos que requerían una lista de argumentos de longitud variable podían manejarse de dos maneras, ninguna de las cuales era particularmente agradable.

  • Primero, si la cantidad máxima de argumentos era pequeña y conocida, entonces podría crear versiones sobrecargadas del método, una para cada forma en que se podría llamar al método. Aunque esto funciona y es adecuado para algunas situaciones, solo se aplica a una clase estrecha de situaciones.
  • En los casos en que la cantidad máxima de argumentos potenciales es mayor o incognoscible, se utilizó un segundo enfoque en el que los argumentos se colocaron en una matriz y luego la matriz se pasó al método. Francamente, ambos enfoques a menudo dieron lugar a soluciones torpes, y se reconoció ampliamente que era necesario un mejor enfoque.

A partir de JDK 5, esta necesidad se abordó mediante la inclusión de una característica que simplificó la creación de métodos que requieren una cantidad variable de argumentos. Esta característica se llama varargs, que es la abreviatura de argumentos de longitud variable (Variable-Length Arguments).

Un método que toma una cantidad variable de argumentos se denomina método varargs. La lista de parámetros para un método varargs no es fija, sino que tiene una longitud variable. Por lo tanto, un método varargs puede tomar una cantidad variable de argumentos.

2. Sintaxis de Varargs

Un argumento de longitud variable se especifica por tres puntos (…). Por ejemplo, aquí está cómo escribir un método llamado vaTest() que toma una cantidad variable de argumentos:

//vaTest() usa un vararg
 static void vaTest(int ... v){
     System.out.println("Número de argumentos: "+v.length);
     System.out.println("Contiene: ");

     for (int i=0; i<v.length;i++)
         System.out.println(" arg "+i+": "+v[i]);
     System.out.println(); 
}

Observe que v se declara como se muestra aquí:

int ... v

Esta sintaxis le dice al compilador que se puede llamar a vaTest() con cero o más argumentos. Además, hace que v se declare implícitamente como una matriz de tipo int[]. Por lo tanto, dentro de vaTest(), se accede a v usando la sintaxis de matriz normal.

3. Ejemplo de Varargs

Aquí hay un programa completo que demuestra vaTest():

Ejemplo:

// Demostración Argumentos Variables en Java
class VarArgs{

    //vaTest() usa un vararg
    static void vaTest(int ... v){
        System.out.println("Número de args: "+v.length);
        System.out.println("Contiene: ");

        for (int i=0; i<v.length;i++)
            System.out.println(" arg "+i+": "+v[i]);
        System.out.println();
    }

    public static void main(String[] args) {
        //Observe cómo vaTest() puede llamarse con un
        //número variable de argumentos
        vaTest(10); //1 arg
        vaTest(1,2,3); //3arg
        vaTest(); //sin arg
    }
}

Salida:

Número de args: 1
Contiene: 
 arg 0: 10

Número de args: 3
Contiene: 
 arg 0: 1
 arg 1: 2
 arg 2: 3

Número de args: 0
Contiene:

Hay dos cosas importantes para notar sobre este programa.

  • Primero, como se explicó, dentro de vaTest(), v se opera como un array. Esto se debe a que v es una matriz. La sintaxis simplemente le dice al compilador que se usará un número variable de argumentos, y que estos argumentos se almacenarán en la matriz mencionada por v.
  • Segundo, en main(), vaTest() se llama con diferentes números de argumentos, incluyendo ningún argumento en absoluto. Los argumentos se colocan automáticamente en una matriz y se pasan a v. En el caso de que no haya argumentos, la longitud de la matriz es cero.

4. Métodos con parámetros normales y parámetros variables

Un método puede tener parámetros “normales” junto con un parámetro de longitud variable. Sin embargo, el parámetro de longitud variable debe ser el último parámetro declarado por el método. Por ejemplo, esta declaración de método es perfectamente aceptable:

int miMetodo(int a, int b, double c, int ... vals)

En este caso, los primeros tres argumentos utilizados en una llamada a miMetodo() se corresponden con los primeros tres parámetros. Entonces, se supone que los argumentos restantes pertenecen a vals. Aquí hay una versión modificada del método vaTest() que toma un argumento regular y un argumento de longitud variable:

Ejemplo:

// Usao de varargs con argumentos estándar
class VarArgs{

    //Aquí msg es un parámetro normal y
    //'v' es un parámetro vararg
    static void vaTest(String msg,int ... v){
        System.out.println(msg+v.length);
        System.out.println("Contiene: ");

        for (int i=0; i<v.length;i++)
            System.out.println(" arg "+i+": "+v[i]);
        System.out.println();
    }

    public static void main(String[] args) {

        vaTest("Un Parámetro: ",10); //1 arg
        vaTest("Tres Parámetro: ",1,2,3); //3arg
        vaTest("Sin Parámetros: "); //sin arg
    }
}

Salida:

Un Parámetro: 1
Contiene: 
 arg 0: 10

Tres Parámetro: 3
Contiene: 
 arg 0: 1
 arg 1: 2
 arg 2: 3

Sin Parámetros: 0
Contiene:

Recuerde, el parámetro varargs debe ser el último. Por ejemplo, la siguiente declaración es incorrecta:

int miMetodo(int a, int b, double c, int ... vals, boolean s) { //Error!

Aquí, hay un intento de declarar un parámetro regular después del parámetro varargs, que es ilegal. Hay una restricción más a tener en cuenta: debe haber solo un parámetro varargs. Por ejemplo, esta declaración tampoco es válida:

int miMetodo(int a, int b, double c, int ... vals, double ... masvals) {
// Error!

El intento de declarar el segundo parámetro varargs es ilegal.

5. Sobrecarga de los métodos Varargs

Puede sobrecargar un método que toma un argumento de longitud variable. Por ejemplo, el siguiente programa sobrecarga vaTest() tres veces:

Ejemplo:

// Usao de varargs con argumentos estándar
class VarArgs3{

    static void vaTest(int ... v){
        System.out.println("vaTest(int ...): "+"Número de args: "+v.length);
        System.out.println("Contiene: ");

        for (int i=0; i<v.length;i++)
            System.out.println(" arg "+i+": "+v[i]);
        System.out.println();
    }

    static void vaTest(boolean ... v){
        System.out.println("vaTest(boolean ...): "+"Número de args: "+v.length);
        System.out.println("Contiene: ");

        for (int i=0; i<v.length;i++)
            System.out.println(" arg "+i+": "+v[i]);
        System.out.println();
    }

    static void vaTest(String msg, int ... v){
        System.out.println("vaTest(String, int ...): "+msg+v.length);
        System.out.println("Contiene: ");

        for (int i=0; i<v.length;i++)
            System.out.println(" arg "+i+": "+v[i]);
        System.out.println();
    }

    public static void main(String[] args) {
        vaTest(1,2,3);
        vaTest("Prueba: ",10,20);
        vaTest(true,false,true);
    }
}

Salida:

vaTest(int ...): Número de args: 3
Contiene: 
 arg 0: 1
 arg 1: 2
 arg 2: 3

vaTest(String, int ...): Prueba: 2
Contiene: 
 arg 0: 10
 arg 1: 20

vaTest(boolean ...): Número de args: 3
Contiene: 
 arg 0: true
 arg 1: false
 arg 2: true

Este programa ilustra las dos formas en que se puede sobrecargar un método varargs.

  • Primero, los tipos del parámetro vararg pueden diferir. Este es el caso de vaTest(int …) y vaTest (boolean …). Recuerde, el hace que el parámetro sea tratado como una matriz del tipo especificado. Por lo tanto, del mismo modo que puede sobrecargar métodos utilizando diferentes tipos de parámetros de matriz, puede sobrecargar métodos varargs utilizando diferentes tipos de variables. En este caso, Java usa la diferencia de tipo para determinar qué método sobrecargado llamar.
  • La segunda forma de sobrecargar un método varargs es agregar uno o más parámetros normales. Esto es lo que se hizo con vaTest(String, int …). En este caso, Java usa tanto el número de argumentos como el tipo de argumentos para determinar a qué método llamar.

6. Varargs y error por ambigüedad

Se pueden producir errores algo inesperados al sobrecargar un método que toma un argumento de longitud variable. Estos errores implican ambigüedad porque es posible crear una llamada ambigua a un método varargs sobrecargado. Por ejemplo, considere el siguiente programa:

// Varargs, Sobrecarga, Ambiguedad
// Este programa tiene un error y no compilará
class VarArgs3{

    //Uso de un int como parámetro vararg
    static void vaTest(int ...v){
        //...
    }
    //Uso de un boolean como parámetro vararg
    static void vaTest(boolean ... v){
        //...
    }

    public static void main(String[] args) {
        vaTest(1,2,3); //Ok
        vaTest(true,false,true); //Ok

        vaTest(); //Error, por ambiguedad!
    }
}

En este programa, la sobrecarga de vaTest() es perfectamente correcta. Sin embargo, este programa no se compilará debido a la siguiente llamada:

vaTest();

Como el parámetro vararg puede estar vacío, esta llamada podría traducirse en una llamada a vaTest(int …) o a vaTest(boolean …). Ambos son igualmente válidos. Por lo tanto, la llamada es intrínsecamente ambiguo.

Aquí hay otro ejemplo de ambigüedad. Las siguientes versiones sobrecargadas de vaTest() son intrínsecamente ambiguas aunque se tome un parámetro normal:

static void vaTest(int ... v){ //...
static void vaTest(int n, int ... v) {//...

Aunque las listas de parámetros de vaTest() difieren, no hay forma de que el compilador pueda resolver la siguiente llamada:

vaTest(1)

¿Esto se traduce en una llamada a vaTest (int …), con un argumento varargs, o en una llamada a vaTest(int, int …) sin argumentos varargs? No hay forma de que el compilador responda esta pregunta. Por lo tanto, la situación es ambigua.

Debido a errores de ambigüedad como los que acabamos de mostrar, a veces tendrá que renunciar a la sobrecarga y simplemente utilizar dos nombres de método diferentes. Además, en algunos casos, los errores de ambigüedad exponen un defecto conceptual en tu código, que puede remediar elaborando con más cuidado una solución.

Varargs
  • Argumentos Variables

Sobre el Autor:

Hey hola! Yo soy Alex Walton y tengo el placer de compartir conocimientos hacía ti sobre el tema de Programación en Java, desde cero, Online y Gratis.

Deja una Respuesta

*

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.