juil.
2008
Java : les var-args
Les var-args (liste d’arguments variable) sont une nouveauté Java 5, qui rentre dans la catégorie des "syntaxic sugar".
Autrement dit, ce n’est pas indispensable, mais ça rend bien service.
Alors, à quoi ça sert ? Principalement à simplifier le passage de tableaux en paramètre des méthodes.
Voyons comment.
Un premier exemple
Prenons un exemple : afficher un ensemble de Strings.
public void printAll(String[] strings) { for (String s : strings) { System.out.println(s); } }
Avec la méthode “historique”, il fallait construire un tableau pour passer les Strings en paramètre, comme ceci :
String[] strings = new String[] {"foo", "bar"}; printAll(strings);
ou constuire le tableau directement dans l’appel :
printAll(new String[] {"foo", "bar"});
Les var-args permettent de simplifier cette écriture.
Il suffit de changer légèrement la signature de la méthode (notez les trois points "…" au lieu des crochets) :
public void printAll(String... strings) { for(String s : strings) { System.out.println(s); } }
Le code d’appel est maintenant plus simple :
printAll("foo", "bar"); printAll("foo", "bar", "baz", "toto");
Un peu de théorie
On peut désormais passer un nombre variable d’arguments (pourvu qu’ils soient tous du type déclaré dans la signature de la méthode, évidemment), sans créer explicitement de tableau ! En revanche, dans le corps de la méthode, la variable var-arg est considéré comme un banal tableau et peut donc être parcourue par un « foreach », fournir sa taille avec la propriété length, etc.
Il y a toutefois deux petites limitations à cette syntaxe :
- Il ne peut y avoir qu’un seul var-arg par signature de méthode
- Le var-arg doit toujours être le dernier paramètre
En pratique, les var-args sont très pratiques pour les setters :
public void setStrings(final String... strings) { this.strings = strings; }
Cette syntaxe peut rendre moins fastidieuse la construction de grappes d'objets reposant lourdement sur des tableaux, comme par exemple lors de l'écriture de mocks pour les tests unitaires. Je vous recommande donc de l’appliquer pour tous vos setters simples prenant des tableaux en paramètre.
En pratique
Combinés aux generics, les var-args permettent de créer des méthodes utilitaires puissantes, flexibles et simples d’utilisation.
Par exemple, voici une méthode permettant de construire une liste à partir des objets passés en paramètre.
public static <T> List<T> toList(T... elements) { if (elements == null) { return Collections.<T> emptyList(); } List<T> list = new ArrayList<T>(); for (T element : elements) { list.add(element); } return list; }
Cette méthode est simple à utiliser :
List<String> strings = Utils.toList("foo", "bar", "baz", "toto");
Commentaires
La méthode toList n'existe-t-elle pas déjà ... genre Arrays.asList() ;)
Je connais bien la méthode Arrays.asList(). Son principal problème est que la liste qu'elle renvoie se base sur un tableau et est donc de taille fixe. On peut très bien l'utiliser si l'on est averti de cette limitation, mais dans le cas contraire, les effets de bord sont relativement difficiles à débugger (l'exception lancée en cas de dépassement de la capacité de la liste est une UnsupportedOperationException...). La méthode utilitaire que je présente comme exemple n'a pas cette limitation.
Je ne connaissais pas cette limitation, mais c'est aussi du au fait que je n'ai utilisé Arrays.asList() que pour créer des listes constantes (static final).
Vu la limitation dont tu parles, c'est peut-être juste pour cet usage qu'elle a été créée.
En tout cas, bravo pour ce blog sur lequel j'apprends quasiment à chaque post !