Méthodes
Cours · programmation Java (école d'ingénieur), chapitre 4 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun
Un programme de quelques lignes tient dans main. Mais dès qu'il grandit, le même calcul revient à plusieurs endroits, les boucles s'emboîtent, et l'on ne sait plus très bien ce que fait chaque morceau. Considérons un professeur qui calcule la moyenne de trois notes pour chacun de ses élèves :
/** Chapitre 4 — sans méthode, le même calcul est recopié trois fois. */
public class Moyennes {
public static void main(String[] args) {
double m1 = (12 + 15 + 9) / 3.0;
double m2 = (8 + 11 + 14) / 3.0;
double m3 = (17 + 16 + 18) / 3.0;
System.out.println("Alice : " + m1);
System.out.println("Bruno : " + m2);
System.out.println("Chloé : " + m3);
}
}
La formule est écrite trois fois. Si l'on décide de pondérer les notes, il faudra la corriger trois fois, sans en oublier une. Une méthode permet d'écrire ce calcul une seule fois, de lui donner un nom, puis de l'utiliser autant de fois que nécessaire :
/** Chapitre 4 — le calcul écrit une seule fois, dans une méthode. */
public class MoyennesMethode {
/** Retourne la moyenne des trois notes a, b et c. */
static double moyenne(int a, int b, int c) {
return (a + b + c) / 3.0;
}
public static void main(String[] args) {
System.out.println("Alice : " + moyenne(12, 15, 9));
System.out.println("Bruno : " + moyenne(8, 11, 14));
System.out.println("Chloé : " + moyenne(17, 16, 18));
}
}
Alice : 12.0
Bruno : 11.0
Chloé : 17.0
Les deux programmes affichent la même chose. Le second est plus court, plus lisible (on lit « moyenne » au lieu de déchiffrer une formule), et plus facile à modifier. Décomposer un programme en méthodes est le premier geste de tout programmeur.
Objectifs du chapitre
- Déclarer une méthode
static: sa signature, son type de retour, ses paramètres, son corps. - Appeler une méthode et utiliser la valeur qu'elle retourne.
- Comprendre le passage des paramètres par valeur et la portée des variables locales.
- Surcharger une méthode, la documenter, la tester.
- Écrire des méthodes récursives et comprendre la pile d'appels.
4.1 Déclarer et appeler une méthode
4.1.1 Anatomie d'une méthode
Une méthode est un bloc d'instructions nommé, qui reçoit des paramètres et peut retourner un résultat. Sa déclaration a la forme :
static TypeDeRetour nomDeLaMethode(Type1 param1, Type2 param2, ...) {
instructions
}
La première ligne est l'en-tête ; le nom et la liste des types des paramètres forment la signature de la méthode ; le bloc entre accolades est son corps.
Reprenons la méthode moyenne :
static: la méthode appartient à la classe et s'appelle sans créer d'objet. C'est le cas de toutes les méthodes de la première partie du livre ; le sens précis de ce mot sera vu au chapitre 8.double: le type de retour, celui de la valeur que la méthode rend à l'appelant.moyenne: son nom, un verbe ou un nom commençant par une minuscule, selon les conventions de Java.(int a, int b, int c): ses trois paramètres formels, chacun avec son type.return (a + b + c) / 3.0;: l'instructionreturncalcule la valeur retournée et termine la méthode.
4.1.2 Appeler une méthode
On appelle une méthode en écrivant son nom suivi, entre parenthèses, des valeurs à donner aux paramètres : ce sont les arguments (ou paramètres effectifs). Dans moyenne(12, 15, 9), les arguments sont , et . L'appel se déroule en quatre temps :
- les arguments sont évalués ;
- leurs valeurs sont recopiées dans les paramètres
a,b,c; - le corps de la méthode s'exécute ;
- à l'instruction
return, la méthode se termine et l'appel est remplacé par la valeur retournée, ici12.0.
Un appel de méthode qui retourne une valeur est donc une expression : on peut l'afficher, l'affecter à une variable, ou s'en servir dans un calcul, comme double ecart = moyenne(12, 15, 9) - moyenne(8, 11, 14);.
À l'appel, il faut autant d'arguments que de paramètres, dans le même ordre, et chaque argument doit être d'un type compatible avec celui du paramètre : identique, ou convertible sans perte (un int vers un double, par exemple). Sinon, le programme ne compile pas.
Le compilateur vérifie cette règle et refuse, par exemple, de passer un nombre décimal à une méthode qui attend un entier :
static int carre(int x) {
return x * x;
}
// ...
System.out.println(carre(2.5));
MauvaisArgument.java:9: error: incompatible types: possible lossy conversion from double to int
System.out.println(carre(2.5));
^
Le message se lit ainsi : à la ligne , conversion « avec perte possible » de double vers int. Le compilateur refuse de tronquer en sans qu'on le lui demande.
4.1.3 Méthodes void
Certaines méthodes n'ont rien à retourner : elles agissent (afficher, modifier un tableau…). Leur type de retour est void (« vide ») :
/** Chapitre 4 — une méthode void, qui agit sans rien retourner. */
public class Saluer {
static void saluer(String nom, int fois) {
for (int i = 0; i < fois; i++) {
System.out.println("Bonjour " + nom + " !");
}
}
public static void main(String[] args) {
saluer("Ada", 2);
saluer("Alan", 1);
}
}
Bonjour Ada !
Bonjour Ada !
Bonjour Alan !
L'appel saluer("Ada", 2) est une instruction, pas une expression. On ne peut donc pas ranger son « résultat » dans une variable :
int x = saluer("Ada", 2); // erreur de compilation : saluer ne retourne rien
Une méthode void peut contenir un return; sans valeur, pour s'arrêter avant la fin.
4.1.4 Toute exécution doit atteindre un return
Une méthode qui retourne une valeur doit la retourner sur tous les chemins d'exécution. Le compilateur le vérifie :
static int signe(int x) {
if (x > 0) return 1;
if (x < 0) return -1;
}
OubliReturn.java:7: error: missing return statement
}
^
Que retourne signe(0) ? Rien n'est prévu, et le compilateur le voit. On corrige en ajoutant return 0; à la fin.
Afficher n'est pas retourner
Une erreur fréquente des débutants consiste à écrire System.out.println(resultat); à la place de return resultat;. La méthode affiche alors la bonne valeur… mais l'appelant ne la reçoit pas, et ne peut pas s'en servir pour un calcul. Une méthode qui calcule doit retourner ; c'est main, ou une méthode d'affichage, qui affiche.
4.2 Paramètres et variables locales
4.2.1 Le passage par valeur
En Java, les arguments sont toujours passés par valeur : le paramètre reçoit une copie de la valeur de l'argument. Modifier le paramètre dans la méthode ne modifie pas la variable de l'appelant.
/** Chapitre 4 — les paramètres sont passés par valeur. */
public class ParValeur {
static void doubler(int x) {
x = 2 * x; // modifie la COPIE locale
System.out.println("dans doubler : x = " + x);
}
static int double2(int x) {
return 2 * x; // on retourne le résultat
}
public static void main(String[] args) {
int n = 5;
doubler(n);
System.out.println("après doubler : n = " + n);
n = double2(n);
System.out.println("après n = double2(n) : n = " + n);
}
}
dans doubler : x = 10
après doubler : n = 5
après n = double2(n) : n = 10
Pour comprendre, il faut savoir où vivent les variables. Chaque appel de méthode reçoit en mémoire une zone d'activation (en anglais stack frame), qui contient ses paramètres et ses variables locales. Ces zones sont empilées dans la pile d'appels : l'appel le plus récent est au sommet, et sa zone disparaît quand il se termine.
La suite du cours est sur Adloun
Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.
Lire la suite du coursEn accès libre, sans inscription.