324 votes

Puis-je passer un tableau comme argument à une méthode avec des arguments variables en Java ?

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 j'aimerais que chaque Object en args à passer comme un nouvel argument. Puisque String.format est également une méthode avec des arguments variables, cela devrait être possible.

Si cela n'est pas possible, existe-t-il une méthode du type String.format(String format, Object[] args) ? Dans ce cas, je pourrais ajouter extraVar a args en utilisant un nouveau tableau et en le passant à cette méthode.

8 votes

Je ne peux pas m'empêcher de me demander pourquoi cette question est du genre "est-ce valable". Vous ne pouviez pas simplement essayer ? N'exagérez pas la question, vous vous ferez plus de mal que de bien.

33 votes

C'est vrai, cela aurait pu être facilement testé. cependant, l'avantage d'une question comme celle-ci est qu'elle expose le sujet et suscite des réponses intéressantes.

3 votes

J'ai en fait essayé le code ci-dessus, avec l'intention de passer le tableau args comme arguments à la méthode. Cependant, je n'ai pas réalisé que j'aurais dû ajouter extraVar à args en premier. Quand on sait que les arguments de variables sont traités comme un tableau (même en dehors de la méthode), c'est bien sûr tout à fait logique.

352voto

polygenelubricants Points 136838

Oui, un T... est seulement un sucre syntaxique pour un T[] .

JLS 8.4.1 Paramètres de format

Le dernier paramètre formel dans une liste est spécial ; il peut être un arité variable indiqué par une elipsis suivant le type.

Si le dernier paramètre formel est un paramètre d'arité variable de type T on considère que l'on définit un paramètre formel de type T[] . La méthode est alors une arité variable méthode. Sinon, il s'agit d'une arité fixe méthode. Les invocations d'une méthode d'arité variable peuvent contenir plus d'expressions d'arguments réels que de paramètres formels. Toutes les expressions d'arguments réels qui ne correspondent pas aux paramètres formels précédant le paramètre d'arité variable seront évaluées et les résultats seront stockés dans un tableau qui sera transmis à l'invocation de la méthode.

Voici un exemple à titre d'illustration :

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, ce qui précède main est valable, parce qu'encore une fois, String... est juste String[] . De plus, comme les tableaux sont covariants, un String[] es un Object[] Vous pouvez donc également appeler ezFormat(args) de toute façon.

Voir aussi


Varargs gotchas #1 : passing null

La façon dont les varargs sont résolus est assez compliquée, et parfois elle fait des choses qui peuvent vous surprendre.

Prenons 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 façon dont les varargues sont résolus, la dernière instruction est invoquée avec la commande objs = null ce qui, bien sûr, causerait NullPointerException con objs.length . Si vous voulez en donner un null à un paramètre varargs, vous pouvez faire l'une des deux choses suivantes :

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

Questions connexes

Voici un échantillon de certaines des questions posées par des personnes qui traitent des varargs :


Vararg gotchas #2 : ajouter des arguments supplémentaires

Comme vous l'avez constaté, 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 de la façon dont les varargues fonctionnent, ezFormat reçoit 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 comme des arguments individuels, et que vous avez aussi besoin d'ajouter un argument supplémentaire, alors 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 d'aide utiles :

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;
}

Vous pouvez maintenant 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 ]"

Varargs gotchas #3 : passer un tableau de primitives

Cela ne "marche" 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. L'autoboxage ne s'applique pas aux tableaux de primitives. Ce qui suit fonctionne :

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

2 votes

L'utilisation de paramètres variadiques Object... rend difficile l'utilisation de signatures supplémentaires car le compilateur identifie une ambiguïté entre les signatures où même un argument primitif peut être autoboxé en Object.

8 votes

Il y a un hic : si votre méthode a un dernier paramètre de type Object... et que vous l'appelez en passant un String[] par exemple. Le compilateur ne sait pas si votre tableau est le premier élément des varargs ou est l'équivalent de tous les varargs. Il va vous avertir.

0 votes

Passage d'un argument de type X[] en une méthode x(X... xs) donne l'avertissement suivant dans Eclipse : Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.

203voto

jasonmp85 Points 3196

Le type sous-jacent d'un variadique méthode function(Object... args) es function(Object[] args) . Sun a ajouté les varargs de cette manière pour préserver la compatibilité ascendante.

Donc vous devriez juste être en mesure d'ajouter extraVar a args et appeler String.format(format, args) .

3 votes

Passage d'un argument de type X[] en une méthode x(X... xs) donne l'avertissement suivant dans Eclipse : Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.

25voto

mdma Points 33973

Il est possible de passer un tableau - en fait, cela revient au même.

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

est la même chose que

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

C'est juste du sucre syntaxique - le compilateur convertit le premier en le second, puisque la méthode sous-jacente s'attend à un tableau pour l'élément vararg paramètre.

Voir

5voto

ebelisle Points 639

Jasonmp85 a raison de passer un tableau différent à String.format . La taille d'un tableau ne peut pas être modifiée une fois qu'il a été construit, donc vous devez 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);

3voto

Srijit Paul Points 31

J'avais le même problème.

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

Et ensuite passé l'obj comme argument varargs. Cela a fonctionné.

2 votes

Veuillez ajouter cela aussi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X