Varargs:
public static void foo(String... string_array) { ... }
versus
Paramètre de tableau unique:
public static void bar(String[] string_array) { ... }
Java 1.6 semble accepter/rejeter les éléments suivants:
String[] arr = {"abc", "def", "ghi"};
foo(arr); // accept
bar(arr); // accept
foo("abc", "def", "ghi"); // accept
bar("abc", "def", "ghi"); // reject
En supposant que ce qui précède est vrai/correct, pourquoi ne pas toujours utiliser des varargs au lieu d'un seul paramètre de tableau? Semble ajouter une touche de flexibilité de l'appelant gratuitement.
Un expert peut-il partager la différence JVM interne, s'il y en a une?
Merci.
Les tableaux existent depuis le début de Java, tandis que les varargs sont un ajout assez récent. Ainsi, beaucoup de codes plus anciens utilisent toujours avec bonheur des tableaux.
Notez également que l'appel d'une méthode vararg générique avec un paramètre de tableau explicite peut produire silencieusement un comportement différent de celui attendu:
public <T> void foo(T... params) { ... }
int[] arr = {1, 2, 3};
foo(arr); // passes an int[][] array containing a single int[] element
Ainsi - en plus de nécessiter beaucoup d'efforts sans aucun avantage clair - il n'est pas toujours souhaitable de remplacer les paramètres de tableau hérités par des varargs.
Sans parler des cas où vous ne pouvez pas, car il y a un autre paramètre après le tableau dans la liste des paramètres de la méthode:
public void foo(String[] strings, String anotherParam) { ... }
Réorganiser les paramètres peut résoudre techniquement cela, mais il casse le code client.
pdate: Effective Java 2nd. Edition, Item 42: Utiliser judicieusement les varargs explique cela plus en détail, donnant également un exemple concret: Arrays.asList()
a été modernisé en Java5 pour avoir des paramètres vararg, qui par inadvertance cassé beaucoup de code existant peut provoquer des surprises lors de l'utilisation de cet idiome (désormais obsolète) pour imprimer un tableau:
System.out.println(Arrays.asList(myArray));
pdate2: Double vérifié la source, et il est dit que le problème se produit avec des tableaux de types primitifs, tels que int[]
. Avant varargs, codez comme ceci:
int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
System.out.println(Arrays.asList(digits));
émettrait une erreur de compilation, car seuls les tableaux de types de référence pouvaient être convertis en List
. Depuis varargs et la modification de asList
, le code ci-dessus se compile sans avertissements, et le résultat inattendu est quelque chose comme "[[I@3e25a5]"
.
La principale raison de ne pas tout spécifier comme varargs est que cela n'a pas toujours de sens. Par exemple, si InputStream.read(byte[])
où défini comme `read (octet ...) alors l'appel suivant serait valide:
myInputStream.read(0, 1, 2, 3);
Cela créerait un tableau d'octets à 4 éléments, le transmettrait puis le supprimerait.
Un vararg est un sucre syntaxique simple pour un tableau.
si vous appelez foo("abc", "def", "ghi");
alors le compilateur l'appellera comme foo(new String[] {"abc", "def", "ghi"});
le compilateur créera un nouveau tableau et le passera à foo()
. On ne peut pas avoir à la fois foo(String...)
et foo(String[])
. Puisque les deux sont fonctionnellement identiques.
dans foo vous spécifiez trois paramètres, vous devez appeler la barre comme ceci:
bar(new String[]{"abc", "def", "ghi"});
de sorte que vous ne l'appeliez qu'avec un paramètre, c'est-à-dire la chaîne [] dans ce cas, cela n'a presque rien à voir avec les internes, votre signature de méthode pour la barre de méthode indique simplement qu'elle n'a qu'un seul paramètre, alors que foo a n paramètres qui sont toutes des chaînes
Voici comment les varargs sont définis. L'extension varargs ne fait pas de chaque fonction d'acceptation de tableau une fonction varargs. Vous devez appeler la barre comme ceci:
bar(new String[]{"abc", "def", "ghi"})
Une autre différence est l'efficacité. Les objets qui sont à l'intérieur d'un tableau explicite ne seront pas invoqués. Cependant, les paramètres d'une liste d'arguments variables sont évalués lorsque la méthode est poussée sur la pile.
Cela apparaît lorsqu'un appel de fonction est passé en tant que paramètre qui renvoie le type utilisé dans la liste des arguments de variable.
Exemple: someMethod (Object ... x) anotherMethod (Object []);
someMethod (a (), b (), c ()); // a, b et c seront invoqués avant d'entrer dans la méthode.
anotherMethod (new Object [] {a (), b (), c ()}); // Les méthodes ne sont invoquées qu'après avoir accédé aux objets.