Rechercher
 

Méthodes à nombre variable de paramètres

Définition de méthodes statiques Mise en oeuvre de méthodes récursives



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

La vidéo

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 %).


Méthodes à nombre variable de paramètres

Un premier exemple de méthode à nombre variable de paramètres

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;
}
$>
la classe 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...).

Appels d'une méthode à nombre variables de paramètres

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

}
Exemple d'utilisation de la méthode System.out.printf

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
$>

Autre syntaxe possible pour invoquer une méthode à nombre variable de paramètres

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

}
Appels de méthodes à nombre variable de paramètres via des tableaux

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.

Implémentation d'une méthode à nombre variable de paramètres

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.

vous aurez souvent à choisir entre mettre en oeuvre de la surcharge de méthode, ou bien définir une méthode à nombre variable de paramètre. Utilisez la première technique quand les algorithmes sont différents les uns des autres et utilisez la seconde quand un algorithme est un cas particulier d'un autre plus général.
 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 ) );
    }           
            
}
Déclaration d'une méthode à nombre variable de paramètres

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
        
    }

}
Un autre exemple de méthode à nombre variable de paramètres

Travaux pratiques

Le sujet

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" );
Code de déclenchement d'une exception

La correction

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

}
Implémentation de méthodes à nombre variable de paramètres


Définition de méthodes statiques Mise en oeuvre de méthodes récursives