Une méthode, un nombre quelconque d'arguments
Parfois vous ne savez pas à l'avance combien d'arguments une méthode va recevoir. Vous voulez max(3, 9) à un instant, puis max(1, 7, 4, 2, 8) juste après. Sans les varargs, il faudrait écrire une surcharge pour chaque nombre d'arguments ou forcer l'appelant à construire un tableau. Les varargs - abréviation d'arguments variables - permettent à une seule méthode d'accepter zéro, une ou plusieurs valeurs du même type.
On les déclare en plaçant trois points (...) après le type du paramètre :
L'appelant passe des valeurs éparses ; à l'intérieur de la méthode numbers est un véritable tableau. C'est toute l'idée : le compilateur regroupe les arguments dans un tableau à votre place.
Les varargs ne sont qu'un tableau
Il n'y a pas de magie à l'exécution. Un paramètre déclaré int... numbers est exactement un int[] une fois que vous êtes dans la méthode. Vous pouvez interroger sa length, l'indexer et le parcourir comme n'importe quel autre tableau.
Comme il s'agit véritablement d'un tableau, vous pouvez aussi confier à une méthode varargs un tableau que vous possédez déjà - elle accepte les deux formes :
Les règles : en dernier et un seul
Deux règles évitent toute ambiguïté avec les varargs, et le compilateur les fait respecter toutes les deux :
- Le paramètre varargs doit être en dernier. Les paramètres ordinaires viennent d'abord, puis le paramètre
...absorbe tout ce qui reste. - Une méthode peut avoir au plus un paramètre varargs. Deux rendraient impossible de savoir où l'un se termine et où le suivant commence.
Ceci compile. Mais placer les varargs en premier - static void log(Object... values, String level) - est une erreur de compilation : varargs parameter must be the last. Le paramètre obligatoire level précède toujours le ....
Là où vous utilisez déjà les varargs
Vous appelez des méthodes varargs depuis le début. System.out.printf et String.format en sont les exemples classiques : leur second paramètre est Object... args :
List.of(...), Arrays.asList(...) et de nombreuses API de style builder sont aussi des varargs. C'est pourquoi vous pouvez leur passer un nombre quelconque d'éléments sans rien envelopper vous-même dans un tableau.
Varargs et surcharge
Les varargs et la surcharge interagissent d'une manière surprenante. Lorsqu'une surcharge ordinaire et une surcharge varargs pourraient toutes deux correspondre à un appel, Java préfère la plus spécifique : la méthode à arité fixe l'emporte :
pick(1, 2) correspond aux deux, mais Java choisit la surcharge sans varargs car elle est la plus proche. La méthode varargs ne s'exécute que lorsqu'aucune surcharge à arité fixe ne correspond. C'est généralement ce que vous voulez, mais cela signifie qu'ajouter une surcharge varargs peut changer en silence la méthode vers laquelle un appel se résout.
Attention aux appels vides et à null
Deux pièges piègent les gens. Premièrement : appeler une méthode varargs sans argument remet à la méthode un tableau vide, et non null - donc numbers.length vaut 0 et la boucle ne fait rien. Vous n'avez pas besoin d'une vérification de null pour le cas sans argument :
Deuxièmement : passer un null littéral est ambigu et dangereux : Java peut interpréter count(null) comme « tout le tableau varargs est null » plutôt que « un élément null », ce qui lève ensuite une NullPointerException quand vous lisez sa length. Si vous voulez réellement dire un unique élément null, soyez explicite avec count((Object) null).
Ensuite : les classes
Les varargs complètent ce que vous pouvez faire avec les paramètres de méthode - des listes d'arguments souples par-dessus la surcharge. Jusqu'ici, les méthodes ont vécu en vrac dans une classe avec static. Vous allez maintenant voir comment les classes fonctionnent réellement : regrouper des données (champs) et un comportement (méthodes) dans vos propres types, ce qui est le cœur de la programmation orientée objet en Java.
Questions fréquentes
Que sont les varargs en Java ?
Les varargs (arguments variables) permettent à une méthode d'accepter un nombre quelconque d'arguments du même type. On les déclare en plaçant ... après le type : int sum(int... numbers). L'appelant peut passer zéro, un ou plusieurs valeurs, et à l'intérieur de la méthode numbers est un tableau ordinaire. C'est du sucre syntaxique : Java rassemble pour vous les arguments épars dans un tableau.
Une méthode Java peut-elle avoir plusieurs paramètres varargs ?
Non. Une méthode peut avoir au plus un paramètre varargs, et il doit être le dernier de la liste des paramètres - par exemple void log(String level, Object... values). S'il n'était pas en dernier, Java ne saurait pas où se termine la partie de longueur variable et où commence le paramètre suivant. Les paramètres ordinaires viennent toujours avant le paramètre ....
Quelle est la différence entre des varargs et un paramètre de type tableau en Java ?
Ils sont presque identiques à l'exécution : un paramètre varargs int... est un int[] à l'intérieur de la méthode. La différence se situe au point d'appel : avec les varargs vous écrivez sum(1, 2, 3) (valeurs éparses), tandis qu'avec un paramètre tableau explicite vous devez construire et passer un tableau, sum(new int[]{1, 2, 3}). Une méthode varargs accepte aussi directement un tableau, c'est donc le choix le plus souple.