J'aimerais pouvoir créer une fonction comme:
class A {
private String extraVar;
public String myFormat(String format, Object ... args){
return String.format(format, extraVar, args);
}
}
Le problème ici est que args
est traité comme Object[]
dans la méthode myFormat
, et constitue donc un argument unique pour String.format
, alors que je voudrais chaque Object
dans args
à transmettre en tant que nouvel argument. Puisque String.format
est également une méthode avec des arguments variables, cela devrait être possible.
Si ce n'est pas possible, existe-t-il une méthode comme String.format(String format, Object[] args)
? Dans ce cas, je pourrais ajouter extraVar
à args
en utilisant un nouveau tableau et le transmettre à cette méthode.
Le type sous-jacent d'une méthode variadique function(Object... args)
estfunction(Object[] args)
. Sun a ajouté varargs de cette manière afin de préserver la compatibilité avec les versions antérieures.
Vous devriez donc pouvoir ajouter extraVar
à args
et appeler String.format(format, args)
.
Oui, un T...
n'est qu'un sucre syntaxique pour un T[]
.
Le dernier paramètre formel d'une liste est spécial; il peut s'agir d'un paramètre variable d'arity , indiqué par un signe suivant le type.
Si le dernier paramètre formel est un paramètre d'arity variable de type
T
, il est envisagé de définir un paramètre formel de typeT[]
. La méthode est alors une méthode à arité variable . Sinon, il s'agit d'une méthode arité fixe . Les invocations d'une méthode d'arity variable peuvent contenir plus d'expressions d'arguments réelles que de paramètres formels. Toutes les expressions d'arguments réelles qui ne correspondent pas aux paramètres formels précédant le paramètre d'arity variable seront évaluées et les résultats stockés dans un tableau qui sera transmis à l'appel de la méthode.
Voici un exemple pour illustrer:
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 ]"
}
Et oui, la méthode main
ci-dessus est valide, car encore une fois, String...
n'est que String[]
. De plus, comme les tableaux sont covariants, un String[]
est un Object[]
, de sorte que vous pouvez également appeler ezFormat(args)
dans les deux sens.
null
La façon dont les varargs sont résolus est assez compliquée, et parfois elle fait des choses qui peuvent vous surprendre.
Considérons cet exemple:
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!!!
En raison de la manière dont les variables sont résolues, la dernière instruction appelle avec objs = null
, ce qui entraînerait bien sûr NullPointerException
avec objs.length
. Si vous souhaitez attribuer un argument null
à un paramètre varargs, vous pouvez effectuer l'une des opérations suivantes:
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
Voici un exemple de certaines des questions que les gens ont posées lorsqu'ils traitent de varargs:
Comme vous l'avez découvert, ce qui suit ne fonctionne pas:
String[] myArgs = { "A", "B", "C" };
System.out.println(ezFormat(myArgs, "Z"));
// prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"
En raison du fonctionnement de varargs, ezFormat
obtient en fait 2 arguments, le premier étant un String[]
, le second étant un String
. Si vous passez un tableau à varargs et que vous voulez que ses éléments soient reconnus en tant qu'arguments individuels et que vous ayez également besoin d'ajouter un argument supplémentaire, vous n'avez pas d'autre choix que de créer un autre tableau qui accueille l'élément supplémentaire.
Voici quelques méthodes utiles d'aide:
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;
}
Maintenant, vous pouvez faire ce qui suit:
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 ]"
Cela ne fonctionne pas:
int[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"
Varargs ne fonctionne qu'avec les types de référence. La sélection automatique ne s'applique pas à un tableau de primitives. Les oeuvres suivantes:
Integer[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"
C'est ok pour passer un tableau - en fait c'est la même chose
String.format("%s %s", "hello", "world!");
est le même que
String.format("%s %s", new Object[] { "hello", "world!"});
C'est juste du sucre syntaxique - le compilateur convertit le premier en second, car la méthode sous-jacente attend un tableau pour le paramètre vararg .
Voir
jasonmp85 a raison de passer un tableau différent à String.format
. La taille d'un tableau ne peut pas être modifiée une fois construite. Vous devez donc passer un nouveau tableau au lieu de modifier le tableau existant.
Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar;
String.format(format, extraVar, args);
J'avais le même problème.
String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;
Et puis passé l'obj comme argument de varargs. Ça a marché.