¿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 solo argumento para String.format, mientras que me gustaría que cada Object en args se pase como un nuevo argumento. Dado que String.format es también un método con argumentos variables, esto debería ser posible.

Si esto no es posible, hay un método como String.format(String format, Object[] args)? En ese caso podría anteponer extraVar a args usando un nuevo array y pasarlo a ese método.

Author: jasonmp85, 2010-05-28

5 answers

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

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

 149
Author: jasonmp85,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-27 21:58:41

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 variable arity, indicado por un elipsis después del 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 variable arity. De lo contrario, es un método de aridad fija. Las invocaciones de un método de aridad variable pueden contener más expresiones de argumento reales que parámetros formales. Todas las expresiones de argumento reales que no corresponden a los parámetros formales que preceden al parámetro variable arity se evaluarán y los resultados se almacenarán en un array 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 anterior main es válido, porque de nuevo, String... es solo String[]. Además, debido a que los arrays son covariantes, a String[] es un Object[], por lo que también puede llamar a ezFormat(args) de cualquier manera.

Véase también


Varargs gotchas #1: pasando {[18]]}

Cómo se resuelven los varargs es bastante complicado, y a veces hace cosas que pueden sorprenderte.

Considere 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 cómo se resuelven los varargs, la última declaració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 lo siguiente:

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

Cuestiones conexas

La siguiente es una muestra de algunas de las preguntas que la gente ha hecho al tratar con varargs:


Vararg gotchas #2: agregar argumentos adicionales

Como has descubierto, 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 funciona varargs, ezFormat en realidad obtiene 2 argumentos, el primero es a String[], el segundo es a 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 cree otro array que acomode el elemento extra.

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

static <T> 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> 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 matriz de primitivas

No "funciona":

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

Varargs solo funciona con tipos de referencia. Autoboxing no se aplica a la matriz de primitivas. Las siguientes obras:

    Integer[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ 1 ][ 2 ][ 3 ]"
 260
Author: polygenelubricants,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:43

Está bien pasar un array-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 compilador convierte el primero en el segundo, ya que el método subyacente espera una matriz para el parámetro vararg.

Véase

 18
Author: mdma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-27 22:17:47

Jasonmp85 tiene razón al pasar una matriz diferente a String.format. El tamaño de una matriz no se puede cambiar una vez construida, 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);
 4
Author: ebelisle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-12 20:36:17

Estaba teniendo el mismo problema.

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

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

 0
Author: Srijit Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-19 13:52:42