Accès rapide :
La vidéo
Un premier exemple de méthode à nombre variable de paramètres
Appels d'une méthode à nombre variables de paramètres
Autre syntaxe possible pour invoquer une méthode à nombre variable de paramètres
Implémentation d'une méthode à nombre variable de paramètres
Travaux pratiques
Le sujet
La correction
Cette vidéo vous montre comment coder des méthodes à nombre variable de paramètres, comme la méthode System.out.printf
par exemple.
Effectivement, la méthode printf
accepte un format (sous forme de chaîne de caractères) puis autant de paramètres que le format contiendra
de points d'injections (ces points d'injections étant introduits par le caractère %
).
Il existe, dans la librairie Java, de nombreuses méthodes à nombre variable de paramètres. Parmi elles, la plus emblématique est certainement
System.out.printf( String format, Object... )
. On reconnait une méthode à nombre variable de paramètres grâce à la syntaxe ...
.
Pour trouver ces méthodes, vous pouvez, bien entendu, consulter la Javadoc. Mais vous pouvez aussi utiliser la commande javap
fournie par
le JDK.
$> javap java.io.PrintStream Compiled from "PrintStream.java" public class java.io.PrintStream extends java.io.FilterOutputStream implements java.lang.Appendable,java.io.Closeable { // Some other method declarations public java.io.PrintStream printf(java.lang.String, java.lang.Object...); public java.io.PrintStream printf(java.util.Locale, java.lang.String, java.lang.Object...); public java.io.PrintStream format(java.lang.String, java.lang.Object...); public java.io.PrintStream format(java.util.Locale, java.lang.String, java.lang.Object...); public java.io.PrintStream append(java.lang.CharSequence); public java.io.PrintStream append(java.lang.CharSequence, int, int); public java.io.PrintStream append(char); public java.lang.Appendable append(char) throws java.io.IOException; public java.lang.Appendable append(java.lang.CharSequence, int, int) throws java.io.IOException; public java.lang.Appendable append(java.lang.CharSequence) throws java.io.IOException; } $>
java.io.PrintStream
, utilisée dans l'exemple ci-dessus, est le type de System.out
, un objet sur lequel la méthode
printf
peut donc être invoquée.
Comme on le constate sur les résultats produits par la commande javap
, il existe deux signatures pour la méthode printf
.
Nous ne considérerons dans ce chapitre que la première signature, celle qui accepte une chaîne de caractères (le format), puis un nombre variable
de paramètres (java.lang.Object...
).
C'est le format qui importe le plus. Effectivement, ce format doit contenir un certain nombre de séquences de caractères commençant toute par le
caractère %
(%d
, %s
, ...). Ces séquences indiquent des points d'injection dans la chaîne correspondant au format.
Pour chaque point d'injection, on replacera la séquence correspondante par un des paramètres spécifié dans l'appel à la méthode.
Voici quelques exemples d'utilisation de cette méthode printf
.
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Demo { public static void main( String [] args ) { System.out.printf( "Un seul paramètre: le format\n" ); System.out.printf( "Le format et un entier: %d\n", 10 ); System.out.printf( "[%d/%d]\n", 10, 3 ); System.out.printf( "%d %5.2f %s\n", 100, 3.141592654, "toto" ); } } |
Quelques explications sont peut-être nécessaires. La ligne 5 est certainnement la forme la plus simple d'utilisation de la méthode printf
car, le format ne spécifie aucun point d'injection : il n'y a donc pas de paramètre supplémentaire. Dans ce cas, n'oubliez pas la séquence de
caractère \n
pour forcer un retour à la ligne.
La ligne 6 définie un format avec un point d'injection de type %d
: il est donc nécessaire, outre le format, de spécifier un autre
paramètre entier, ici de valeur 10. Pour information, le %d
indique qu'on souhaite injecter un paramètre entier en base décimale.
Vous auriez pu utiliser d'autres bases numériques, par exemple %x
aurait indiqué qu'on attendait un paramètre entier exprimé en base
hexadécimale.
La ligne suivante, la ligne 7, propose un format avec de points d'injection : il faut donc deux paramètres supplémentaires. L'ordre est important :
la valeur 10
sera injectée en lieu et place du premier %d
et la valeur 3
, en lieu et place du second %d
.
Enfin, le dernier appel à printf
nécessite trois paramètres supplémentaires car il y a trois points d'injection spécifiés.
Le premier point d'injection attend un entier, le second attend une valeur flottante formatée sur 5 caractères au total et deux pour la partie décimale.
Quant au troisième point d'injection, il attend une valeur de type chaîne de caractères. On trouve bien les trois valeurs attendues à la suite du format.
Voici les résultats produit par notre exemple de code.
$> java Demo Un seul paramètre: le format Le format et un entier: 10 [10/3] 100 3,14 toto $>
En Java, la notion de méthode à nombre variable de paramètres n'est que du « sucre syntaxique » : en fait, une telle méthode n'est qu'une méthode classique qui va accepter un tableau de valeurs. Ainsi, vous pourrez passer autant de valeurs que souhaité dans le tableau. Voici le même programme que précédemment, mais peu revisité.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Demo { public static void main( String ... args ) { System.out.printf( "Un seul paramètre: le format\n" ); System.out.printf( "Le format et un entier: %d\n", new Object[] { 10 } ); System.out.printf( "[%d/%d]\n", new Object[] { 10, 3 } ); Object [] params = { 100, 3.141592654, "toto" }; System.out.printf( "%d %5.2f %s\n", params ); } } |
Quelques explications sur les changements par rapport à la première version sont peut-être nécessaires. Ces changements commencent dès la ligne 3.
Effectivement, j'utilise la syntaxe String...
pour indiquer que le main
accepte un nombre variable d'arguments, et cela
marche très bien.
Pour le printf
suivant, rien ne change, étant donné qu'il n'y a pas de paramètres supplémentaires hormis le format.
Ensuite, les trois affichages suivants utilisent un tableau de données, ce tableau étant dimensionné en fonction du nombre de points d'injections présents
dans le format. Notez que pour le dernier affichage, le tableau est initialement associé à une variable et ensuite cette variable est passée à l'appel
à printf
.
Dans le chapitre précédent, nous avions utilisé la surcharge pour fournir deux manières de calculer un minimum (soit avec deux valeurs à comparer, soit avec trois). En fait, on aurait pu remplacer ces deux méthodes par une seule, mais à nombre variable de paramètres. Dans ce cas, la signature de la méthode aurait était telle que montré dans l'exemple ci-dessous.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class Demo { public static int mini( int... values ) { System.out.println( "Nb elements: " + values.length ); System.out.println( "1st value: " + values[0] ); return 0; } public static void main( String [] args ) { System.out.println( mini( 3 ) ); System.out.println( mini( 3, 5 ) ); System.out.println( mini( 3, 5, 2 ) ); System.out.println( mini( 3, 5, 2, 4 ) ); System.out.println( mini( 3, 5, 2, 4, 1 ) ); } } |
Comme vous l'avez remarqué dans l'exemple ci-dessus, les paramètres passés sont accessible à partir du tableau values
: et oui,
on a bien à faire à un tableau. Ce n'est que du « sucre syntaxique », comme je l'ai déjà dit. On peut donc très facilement connaître le nombre
de paramètres passés à la méthode et l'on facilement accéder à chacun d'entre eux. Voici les résultats produits par l'exemple précédent.
Le TP qui suit vous propose de correctement finaliser cette méthode.
$> java Demo Nb elements: 1 1st value: 3 0 Nb elements: 2 1st value: 3 0 Nb elements: 3 1st value: 3 0 Nb elements: 4 1st value: 3 0 Nb elements: 5 1st value: 3 0 $>
Voici un autre exemple qui propose d'ajouter tous les entiers passés en paramètres d'une méthode add
. Remarquez bien que dans ce
cas, j'ai préféré utiliser un « for each ».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class VarParams { public static int add( int ... values ) { int accumulator = 0; for ( int val : values ) { accumulator += val; } return accumulator; } public static void main(String ... args) { int [] values = { 10, 20, 30, 40, 50 }; System.out.println( add( values ) ); System.out.println( add( new int[] { 10,20,30,40,50 } ) ); System.out.println( add() ); // Affiche 0 System.out.println( add( 10 ) ); // Affiche 10 System.out.println( add( 10, 20 ) ); // Affiche 30 System.out.println( add( 10, 20, 30 ) ); // Affiche 60 } } |
Afin de s'entrainer, je vous propose de reprendre la correction proposée à la fin du chapitre précédent.
L'idée est donc de remplacer les deux méthodes mini
par une seule méthode à nombre variable de paramètres et de remplacer notre méthode
maxi
par une seconde méthode à nombre variable de paramètres. Prenez soin, dans les deux méthodes, de vérifier que vous avez bien au moins
un paramètre de passé à la méthode. Si ce n'est pas le cas, utilisez la ligne de code suivante pour déclencher une erreur (une exception ; nous
reviendrons plus tard sur ce concept).
1 |
throw new RuntimeException( "This method require at least one parameter" ); |
Voici donc ma correction. Notez que je n'ai laissé que les codes relatifs aux méthodes mini
et maxi
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
public class Mathematiques { public static int mini( int... values ) { if ( values.length == 0 ) { throw new RuntimeException( "This method require at least one parameter" ); } int result = values[0]; for( int i=1; i<values.length; i++ ) { if ( values[i] < result ) result = values[i]; } return result; } public static int maxi( int... values ) { if ( values.length == 0 ) { throw new RuntimeException( "This method require at least one parameter" ); } int result = values[0]; for( int i=1; i<values.length; i++ ) { if ( values[i] > result ) result = values[i]; } return result; } // Les autres méthodes ... public static void main( String [] args ) { System.out.println( "mini( 3 ) == " + mini( 3 ) ); System.out.println( "mini( 3, 5 ) == " + mini( 3, 5 ) ); System.out.println( "mini( 3, 5, 2 ) == " + mini( 3, 5, 2 ) ); System.out.println( "mini( 3, 5, 2, 4 ) == " + mini( 3, 5, 2, 4 ) ); System.out.println( "mini( 3, 5, 2, 4, 1 ) == " + mini( 3, 5, 2, 4, 1 ) ); System.out.println( "maxi( 3 ) == " + maxi( 3 ) ); System.out.println( "maxi( 3, 5 ) == " + maxi( 3, 5 ) ); System.out.println( "maxi( 3, 5, 2 ) == " + maxi( 3, 5, 2 ) ); System.out.println( "maxi( 3, 5, 2, 4 ) == " + maxi( 3, 5, 2, 4 ) ); System.out.println( "maxi( 3, 5, 2, 4, 1 ) == " + maxi( 3, 5, 2, 4, 1 ) ); // Les autres tests ... return; } } |
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :