Déclaration et appel de procédures



Nous avons déjà présenté des exemples très simples de procédures (sans paramètres) lorsque nous avons introduit les sous-programmes non évènementiels.

Rappelons que les procédures représentent une catégorie de sous-programmes non évènementiels. Elles se distinguent des fonctions, une autre catégorie de sous-programme que nous aborderons ultérieurement.

L'objectif de cette partie du cours est de présenter les procédures non évènementielles de manière générale. Nous allons donc aborder ici le cas des procédures non évènementielles avec paramètres que nous introduiront par un exemple.



Exemple de procédures avec paramètres

Pour montrer l'intérêt des paramètres dans un sous-programme, nous allons utiliser deux versions d'un même projet (sans intérêt autre que pédagogique !) qui permet d'afficher l'adresse mail d'une personne de nom et prénom donné.

Voici l'interface graphique de ce projet:

Mail.jpg, 18kB

Le bouton SFR affiche l'adresse mail chez sfr, alors que le bouton FREE affiche l'adresse mail chez free.

La première version du projet utilise uniquement des procédures évènementielles. Elle se trouve dans le dossier

Exemple-Java-Sous-Programme/Mail-Version1

La deuxième version utilise une procédure non évènementielle paramètrée. Elle se trouve dans le dossier

Exemple-Java-Sous-Programme/Mail-Version2

Première version du projet

La première version contient deux procédures évènementielles (une pour chaque bouton). Voici le code de la procédure évènementielle associée au bouton SFR:

private void BT_SFRActionPerformed( ...) {                                       
  String prenom, nom;
  prenom = es.Lire (CT_Prenom);
  nom = es.Lire (CT_Nom);
  es.Afficher (prenom+"."+nom+"@sfr.fr", CT_Mail); 
 }   

et voici celle associée au bouton FREE:

private void BT_FREEActionPerformed(...) {                                        
 String prenom, nom;
  prenom = es.Lire (CT_Prenom);
  nom = es.Lire (CT_Nom);
  es.Afficher (prenom+"."+nom+"@free.fr", CT_Mail); 
 }  

On constate que les codes de ces deux procédures évènementielles se ressemblent énormément. Mise à part le nom de la procédure, la seule chose qui change est le nom de l'opérateur (en blanc dans le code ci-dessus) dans l'affichage de l'adresse mail.

En gros, on écrit deux fois le même code pour faire la même chose.

Deuxième version du projet

En utilisant une procédure paramètrée, on peut éviter cette répétition inutile de code. C'est ce que nous avons fait dans la deuxième version du projet.

Voici cette procédure:

void AfficherLeMailChez (String operateur) {
String prenom, nom;
  prenom = es.Lire (CT_Prenom);
  nom = es.Lire (CT_Nom);
  es.Afficher (prenom+"."+nom+"@"+operateur+".fr", CT_Mail);
 } 

Elle permet d'afficher le mail chez n'importe quel opérateur (représenté par le paramètre operateur). Nous avons en quelque sorte généralisé les deux procédures évènementielles de la première version: pour obtenir l'adresse email, il suffit de concaténer le prénom, la chaine ".", le nom, le caractère "@", l'opérateur et la chaine ".fr".

Le code des deux procédures évènementielles se résume alors à l'appel de cette procédure avec deux valeurs de paramètres différents:

private void BT_SFRActionPerformed(...) {                                       
  AfficherLeMailChez ("sfr");
  }                                      

private void BT_FREEActionPerformed(...) {                                        
    AfficherLeMailChez ("free");
 }  
 

Les valeurs des paramètres à l'appel ("sfr" et "free" dans notre exemple) sont les paramètres effectifs à ne pas confondre avec les paramètres formels: ce sont les paramètres déclarés dans l'entête de la procédure. Dans notre exemple, il n'y a qu'un seul paramètre formel (operateur de type String).

Exécution de la deuxième version

Voyons à présent comment tout cela fonctionne à l'exécution. Imaginons que l'utilisateur saisisse son prénom ("eric"), son nom ("thirion"), puis qu'il clique sur le bouton FREE.

  1. la procédure évènementielle BT_FREEActionPerformed est appelée.
  2. Cette procédure contient une instruction d'appel à la procédure AfficherLeMailChez avec "free" comme paramètre effectif. C'est alors qu'a lieu ce que l'on appel le passage de paramètre:
    1. l'ordinateur alloue de la mémoire au paramètre formel (operateur)
    2. le paramètre effectif est recopié dans le paramètre formel. Dans notre cas, operateur prendra donc la valeur "free".
  3. les instructions contenues dans la procédure AfficherLeMailChez sont exécutées:
    1. le prénom est lu depuis le champ de texte CT_Prenom et recopié dans la variable locale prenom.
    2. le nom est lu depuis le champ de texte CT_Nom et recopié dans la variable locale nom.
    3. l'instruction d'affichage de l'adresse mail est exécutée. Comme la valeur du paramètre formel operateur est "free", cela va provoquer l'affichage de l'adresse "eric.thirion@free.fr".
  4. rappelons que lorsqu'un sous-programme a fini de s'exécuté, le mécanisme de retour de sous-programme a lieu. C'est à ce moment que l'espace mémoire alloué aux paramètres et aux variables locales est libéré.

En fait, les paramètres formels d'un sous-programme se comportent comme des variables locales. Vous pouvez donc considérer que tout ce qui a été dit au sujet des variables locales s'applique également aux paramètres formel.

Principes généraux

Déclaration d'une procédure

De manière générale, une procédure java peut se déclarer de la manière suivante:


void NomDeLaProcédure ( liste des paramètres )
{ Déclaration des variables locales
  Instructions
}

Rappelons que la première ligne est l'entête de la procédure. Elle est formée du mot clef void suivi du nom de la procédure et d'une liste optionnelle de paramètres entre parenthèse.

La partie entre { et } est le corps de la procédure. Elle contient la déclaration des variables locales (optionnelle) ainsi que les instructions à exécuter.

Déclaration des paramètres

La liste des paramètres peut être vide ou non. Mais dans tout les cas de figure, les parenthèses sont obligatoires. Une procédure sans paramètre s'écrira donc comme ceci:


void NomDeLaProcédure (  )
{ Déclaration des variables locales
  Instructions
}

S'il n'y a qu'un seul paramètre, on précise son type puis son nom dans les parenthèses:


void NomDeLaProcédure (Type Nom)
{ Déclaration des variables locales
  Instructions
}

S'il y a plusieurs paramètres, les couples Type Nom de chacun d'eux sont séparés par des virgules:


void NomDeLaProcédure (Type Nom, Type Nom, ...., Type Nom)
{ Déclaration des variables locales
  Instructions
}

Ecriture d'un appel de procédure
L'appel d'une procédure est formé du nom de cette procédure suivi d'une liste de paramètres effectifs entre parenthèses.

   NomDeLaProcédure ( liste des paramètres effectifs );

Notez que les parenthèses sont obligatoires, même si la procédures ne possède par de paramètres. Un appel de procédure sans paramètre s'écrit donc:


   NomDeLaProcédure ( );

Dans l'exemple très simple que nous avons présenté, les paramètres effectifs étaient des chaines de caractères et il n'y en avait qu'un seul par appel. De manière générale, il peut y avoir plusieurs paramètres effectifs et d'autre part ces paramètres effectifs ne sont pas necéssairement de simples littéraux mais peuvent être des expressions. Pour définir la liste des paramètres effectifs de la manière la plus générale possible, nous dirons donc que c'est une liste d'expressions séparées par des virgules:


   expression1,...., expressionN 

Pour que l'appel de procédure soit compilable (et exécutable !), deux conditions doivent être satisfaites:

Voici par exemple une procédure qui possède trois paramètres formels (p, n ,o) de type chaine de caractères:

void FormerMail (String p, String n , String o);
begin
    mail := p+'.'+n+'@'+o+'.fr';
end;

Cette procédure forme une adresse mail à partir de trois paramètres:p (le prénom), n (le nom) et o (l'opérateur). Le résultat est stocké dans la variable globale mail.

En supposant que Prenom1, Prenom2 et Nom soient des variables de type chaine de caractères, elle pourrait être appelée de la manière suivante:


  FormerMail (Prenom1+"-"+Prenom2, Nom, "free");

Le premier paramètre effectif est une expression de type chaine de caractères, le deuxième une variable de type chaine de caractères et le troisième, un littéral de type chaine de caractères. Ces trois paramètres effectifs sont donc compatibles avec les paramètres formels.

Par contre, elle ne pourra être appelée d'aucune des manières suivantes:


    FormerMail (Prenom1, Nom);

    FormerMail (Prenom1, Nom, 9);
    

En effet, dans le premier appel le nombre de paramètres effectifs n'est pas égal au nombre de paramètres formels et dans le deuxième, le type du troisième paramètre effectif (numérique) n'est pas compatible avec le type du troisième paramètre formel.

Exception pour les types numériques

Pour les paramètres de types numériques, le type d'un paramètre formel peut être différent de celui du paramètre effectif de même position. Plus précisément, si un paramètre formel est de type double, le paramètre effectif correspondant peut être une expression numérique de type int ( voir type des expressions numériques). Par contre l'inverse n'est pas possible: si un paramètre formel est de type int, le paramètre effectif correspondant ne peut pas être de type double.

Nous retrouvons ici les règles définissant une affectation valide.

Exécution d'un appel de procédure
Principe du retour à la procédure appelante

Un appel de procédure est toujours contenu dans une autre procédure, que nous appelerons la procédure appelante.

Lorsqu'un appel de procédure est exécuté, le processeur interrompt momentanément l'exécution de la procédure appelante pour aller exécuter la procédure appelée. Après avoir exécuté les instructions de cette procédure, il reprend l'exécution de la procédure appelante à partir de l'instruction qui suivait l'appel (figure).
Passage des paramètres et exécution de l'appel

Les paramètres formels d'un sous-programme peuvent être considérés comme des variables locales. Donc tout ce que nous avons dit sur les variables locales est également valables pour les paramètres. En particulier:

L'exécution d'un appel de procédure provoque les opérations suivantes: