Varargs à Java

1. Introduction

Les Varargs ont été introduits dans Java 5 et fournissent un raccourci pour les méthodes qui prennent en charge un nombre arbitraire de paramètres d'un type.

Dans cet article, nous verrons comment nous pouvons utiliser cette fonctionnalité Java principale.

2. Avant Varargs

Avant Java 5, chaque fois que nous voulions passer un nombre arbitraire d'arguments, nous devions passer tous les arguments dans un tableau ou implémenter N méthodes (une pour chaque paramètre supplémentaire):

public String format() { ... } public String format(String value) { ... } public String format(String val1, String val2) { ... }

3. Utilisation de Varargs

Varargs nous aide à éviter d'écrire du code standard en introduisant la nouvelle syntaxe qui peut gérer automatiquement un nombre arbitraire de paramètres - en utilisant un tableau sous le capot.

Nous pouvons les définir à l'aide d'une déclaration de type standard, suivie d'une ellipse:

public String formatWithVarArgs(String... values) { // ... }

Et maintenant, nous pouvons appeler notre méthode avec un nombre arbitraire d'arguments, comme:

formatWithVarArgs(); formatWithVarArgs("a", "b", "c", "d");

Comme mentionné précédemment, les varargs sont des tableaux, nous devons donc travailler avec eux comme nous le ferions avec un tableau normal.

4. Règles

Les Varargs sont simples à utiliser. Mais il y a quelques règles que nous devons garder à l'esprit:

  • Chaque méthode ne peut avoir qu'un seul paramètre varargs
  • L' argument varargs doit être le dernier paramètre

5. Pollution en tas

L'utilisation de varargs peut conduire à ce que l'on appelle une pollution en tas. Pour mieux comprendre la pollution en tas, considérez cette méthode varargs :

static String firstOfFirst(List... strings) { List ints = Collections.singletonList(42); Object[] objects = strings; objects[0] = ints; // Heap pollution return strings[0].get(0); // ClassCastException }

Si nous appelons cette méthode étrange dans un test:

String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList()); assertEquals("one", one);

Nous obtiendrions une ClassCastException même si nous n'avons même pas utilisé de cast de type explicite ici:

java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String

5.1. Utilisation sûre

Chaque fois que nous utilisons varargs , le compilateur Java crée un tableau pour contenir les paramètres donnés. Dans ce cas, le compilateur crée un tableau avec des composants de type générique pour contenir les arguments.

Lorsque nous utilisons des varargs avec des types génériques, car il existe un risque potentiel d'exception fatale à l'exécution, le compilateur Java nous avertit d'une possible utilisation de varargs non sécurisée :

warning: [varargs] Possible heap pollution from parameterized vararg type T

L' utilisation de varargs est sûre si et seulement si:

  • Nous ne stockons rien dans le tableau créé implicitement. Dans cet exemple, nous avons stocké une liste dans ce tableau
  • Nous ne laissons pas une référence au tableau généré échapper à la méthode (nous en parlerons plus tard)

Si nous sommes sûrs que la méthode elle-même utilise en toute sécurité les varargs, nous pouvons utiliser @SafeVarargs pour supprimer l'avertissement.

En termes simples, l' utilisation des varargs est sûre si nous les utilisons pour transférer un nombre variable d'arguments de l'appelant à la méthode et rien de plus!

5.2. Échapper à la référence Varargs

Considérons une autre utilisation non sécurisée de varargs :

static  T[] toArray(T... arguments) { return arguments; }

Au début, il peut sembler que la méthode toArray est totalement inoffensive. Cependant, comme il laisse le tableau varargs s'échapper vers l'appelant, il viole la deuxième règle des varargs sûrs .

Pour voir comment cette méthode peut être dangereuse, utilisons-la dans une autre méthode:

static  T[] returnAsIs(T a, T b) { return toArray(a, b); }

Ensuite, si nous appelons cette méthode:

String[] args = returnAsIs("One", "Two");

Nous obtiendrions, encore une fois, une ClassCastException. Voici ce qui se passe lorsque nous appelons la méthode returnAsIs :

  • Pour passer a et b à la méthode toArray , Java doit créer un tableau
  • Puisque l' Object [] peut contenir des éléments de n'importe quel type, le compilateur en crée un
  • La méthode toArray renvoie l' Object [] donné à l'appelant
  • Puisque le site d'appel attend un String [], le compilateur essaie de convertir l' objet [] en String attendu [] , d'où le ClassCastException

Pour une discussion plus détaillée sur la pollution en tas, il est fortement recommandé de lire le point 32 de Effective Java par Joshua Bloch.

6. Conclusion

Varargs peut faire disparaître beaucoup de passe-partout en Java.

Et, grâce à leur autoboxing implicite vers et depuis Array, ils jouent un rôle dans la pérennité de notre code.

Comme toujours, tous les exemples de code de cet article peuvent être disponibles dans notre référentiel GitHub.