¿Puedo pasar una matriz como argumentos a un método con argumentos variables en Java?

Me gustaría poder crear una función como:

class A { private String extraVar; public String myFormat(String format, Object ... args){ return String.format(format, extraVar, args); } } 

El problema aquí es que args se trata como Object[] en el método myFormat , y por lo tanto es un único argumento para String.format , mientras que me gustaría que cada Object en args se pase como un nuevo argumento. Como String.format es también un método con argumentos variables, esto debería ser posible.

Si esto no es posible, ¿hay algún método como String.format(String format, Object[] args) ? En ese caso, podría extraVar a args usando una nueva matriz y pasarla a ese método.

El tipo subyacente de una function(Object... args) método variadica function(Object... args) es function(Object[] args) . Sun agregó varargs de esta manera para preservar la compatibilidad con versiones anteriores.

Así que solo deberías poder extraVar a args y llamar a String.format(format, args) .

Sí, un T... es solo un azúcar sintáctico para un T[] .

JLS 8.4.1 Parámetros de formato

El último parámetro formal en una lista es especial; puede ser un parámetro de aridad variable , indicado por una elipsis que sigue el tipo.

Si el último parámetro formal es un parámetro de aridad variable de tipo T , se considera que define un parámetro formal de tipo T[] . El método es entonces un método de arity variable . De lo contrario, es un método arity fijo . Las invocaciones de un método de aridad variable pueden contener expresiones de argumento más reales que los parámetros formales. Todas las expresiones de argumentos reales que no se corresponden con los parámetros formales que preceden al parámetro arity variable se evaluarán y los resultados se almacenarán en una matriz que se pasará a la invocación del método.

Aquí hay un ejemplo para ilustrar:

 public static String ezFormat(Object... args) { String format = new String(new char[args.length]) .replace("\0", "[ %s ]"); return String.format(format, args); } public static void main(String... args) { System.out.println(ezFormat("A", "B", "C")); // prints "[ A ][ B ][ C ]" } 

Y sí, el método main anterior es válido, porque de nuevo, String... es simplemente String[] . Además, como las matrices son covariantes, un String[] es un Object[] , por lo que también puede llamar a ezFormat(args) cualquier dirección.

Ver también

  • Guía de lenguaje Java / varargs

Varargs gotchas # 1: pasar null

Cómo se resuelven las varargs es bastante complicado, y algunas veces hace cosas que te pueden sorprender.

Considera este ejemplo:

 static void count(Object... objs) { System.out.println(objs.length); } count(null, null, null); // prints "3" count(null, null); // prints "2" count(null); // throws java.lang.NullPointerException!!! 

Debido a la forma en que se resuelven los varargs, la última instrucción invoca con objs = null , que por supuesto causaría NullPointerException con objs.length . Si desea dar un argumento null a un parámetro varargs, puede hacer cualquiera de los siguientes:

 count(new Object[] { null }); // prints "1" count((Object) null); // prints "1" 

Preguntas relacionadas

La siguiente es una muestra de algunas de las preguntas que las personas han hecho al tratar con varargs:

  • ¿error con varargs y sobrecarga?
  • Cómo trabajar con varargs y reflexión
  • Método más específico con coincidencias de arity fijo / variable (varargs)

Vararg gotchas # 2: agregar argumentos adicionales

Como ya descubrió, lo siguiente no “funciona”:

  String[] myArgs = { "A", "B", "C" }; System.out.println(ezFormat(myArgs, "Z")); // prints "[ [Ljava.lang.String;@13c5982 ][ Z ]" 

Debido a la forma en que funcionan los varargs, ezFormat realidad obtiene 2 argumentos, el primero es un String[] , el segundo es un String . Si está pasando una matriz a varargs, y desea que sus elementos sean reconocidos como argumentos individuales, y también necesita agregar un argumento adicional, entonces no tiene más remedio que crear otra matriz que acomode el elemento adicional.

Aquí hay algunos métodos útiles de ayuda:

 static  T[] append(T[] arr, T lastElement) { final int N = arr.length; arr = java.util.Arrays.copyOf(arr, N+1); arr[N] = lastElement; return arr; } static  T[] prepend(T[] arr, T firstElement) { final int N = arr.length; arr = java.util.Arrays.copyOf(arr, N+1); System.arraycopy(arr, 0, arr, 1, N); arr[0] = firstElement; return arr; } 

Ahora puedes hacer lo siguiente:

  String[] myArgs = { "A", "B", "C" }; System.out.println(ezFormat(append(myArgs, "Z"))); // prints "[ A ][ B ][ C ][ Z ]" System.out.println(ezFormat(prepend(myArgs, "Z"))); // prints "[ Z ][ A ][ B ][ C ]" 

Varargs gotchas # 3: pasando una serie de primitivos

No “funciona”:

  int[] myNumbers = { 1, 2, 3 }; System.out.println(ezFormat(myNumbers)); // prints "[ [I@13c5982 ]" 

Varargs solo funciona con tipos de referencia. El autoboxing no se aplica al conjunto de primitivas. Los siguientes trabajos:

  Integer[] myNumbers = { 1, 2, 3 }; System.out.println(ezFormat(myNumbers)); // prints "[ 1 ][ 2 ][ 3 ]" 

Está bien pasar una matriz, de hecho equivale a lo mismo

 String.format("%s %s", "hello", "world!"); 

es lo mismo que

 String.format("%s %s", new Object[] { "hello", "world!"}); 

Es solo azúcar sintáctico: el comstackdor convierte el primero en el segundo, ya que el método subyacente espera una matriz para el parámetro vararg .

Ver

  • Varargs – Documentación J2SE 1.5

jasonmp85 tiene razón acerca de pasar una matriz diferente a String.format . El tamaño de una matriz no se puede modificar una vez que esté construido, por lo que tendría que pasar una nueva matriz en lugar de modificar la existente.

 Object newArgs = new Object[args.length+1]; System.arraycopy(args, 0, newArgs, 1, args.length); newArgs[0] = extraVar; String.format(format, extraVar, args); 

Estaba teniendo el mismo problema.

 String[] arr= new String[] { "A", "B", "C" }; Object obj = arr; 

Y luego pasó el argumento obj como varargs. Funcionó.