Es posible implementar métodos con un número variable de argumentos en Java, desde la versión 5.
Las condiciones a cumplir son las siguientes:
- Los parámetros variables tienen todos el mismo tipo (o son instancias del mismo objeto).
- Hay cero o más parámetros variables.
- Sólo hay un conjunto de parámetros variables.
- El conjunto de parámetros variables viene al final de la definición del método.
Como ejemplo, la definición del método java.io.PrintStream.printf():
public PrintStream printf(String format,
Object... args)
Uso
Veamos un ejemplo sencillo: un método que devuelve la suma de un número variable de enteros:
public static int sum(int... args)
{
int result=0;
for(int a:args)
{
result+=a;
}
return result;
}
Ejemplo de uso del método:
System.out.printf("0 %d\n", sum()); // prints "0 0"
System.out.printf("1 %d\n", sum(1)); // prints "1 1"
System.out.printf("2 %d\n", sum(1, 2)); // prints "2 3"
System.out.printf("3 %d\n", sum(1, 2, 3)); // prints "3 6"
System.out.printf("4 %d\n", sum(1, 2, 3, 4)); // prints "4 10"
Supongamos que queremos forzar a que haya, al menos, dos enteros (no tiene sentido la suma de 0 ó 1 enteros):
public static int sum(int arg0, int arg1, int... args)
{
int result=arg0+arg1;
for(int a:args)
{
result+=a;
}
return result;
}
Ahora no podemos llamar a la rutina sin argumentos. Un ejemplo de llamada:
System.out.printf("6 %d\n", sum(1, 2, new int[]{2, 3, 4, 5})); // prints "5 17"
Object
Uso básico con objetos:
public static int objector(Object... args)
{
return args.length;
}
Probamos con unas cadenas (String):
String[] strings = new String[]{"one", "two", "three"};
Object[] objects = new Object[]{Integer.valueOf(1), Boolean.TRUE, "three"};
System.out.printf("strings %d\n", objector(strings)); // prints "strings 3"
System.out.printf("objects %d\n", objector(objects)); // prints "objects 3"
De la misma manera, si requerimos al menos un objeto:
public static int objector(Object arg0, Object... args)
{
return args.length;
}
Si ejecutamos los printf del ejemplo de código anterior, utilizando la nueva versión de la rutina objector, veremos que devuelve una longitud cero. Esto se debe a que el array es un objeto en sí, y está siendo pasado a la rutina como primer argumento.
En un caso como este, podemos manejar el caso en que el número de argumentos es igual a cero de esta manera:
public static void objector(Object... args)
{
if(args.length==0)
{
// special case
}
else
{
// handle arguments
}
}
En este caso, un mal uso quedaría de manifiesto en tiempo de compilación. Esto te da la opción de cambiar la interfaz.
Conclusión
Ya que los objetos pasados como argumentos van a ser tratados como un array de tipo Object[] (utilizando reflexión), parece sólo tiene sentido utilizar la versión Object… varargs si el método forma parte de un API y va a ser utilizado por otros.
Autoboxing
Otra cuestión a tener en cuenta es que podemos utilizar el Autoboxing, también introducido en la versión 5 de Java. Esto permite la conversión automática entre tipos y sus objetos correspondientes. Esto funciona si, por ejemplo, pasamos varios objetos Integer a una rutina con argumentos int… args. Sin embargo, no funciona si pasamos un Integer[], pues Java no puede convertirlo automáticamente a int[].
public static int inter(int... args)
{
return args.length;
}
int[] ints = new int[]{ 1, 2, 3, 4, 5 };
Integer[] integers = new Integer[]{ 1, 2, 3, 4, 5 };
System.out.printf("ints %d\n", inter(ints)); // prints "ints 5"
System.out.printf("Integer %d\n", inter(Integer.valueOf(1), Integer.valueOf(2))); // prints Integer 2"
System.out.printf("Integer[] %d\n", inter(integers)); // compiler error
Si que funcionaría si lo hiciéramos al revés. Es decir, si el argumento esperado es de tipo Integer… args, podemos pasar un int[].
Vía | javaranch