Le rôle des boucles est de répéter un certain nombre de fois les mêmes opérations. Tous les programmes, ou presque, ont besoin de ce type de fonctionnalité. Nous utiliserons les boucles pour permettre à un programme de recommencer depuis le début, pour attendre une action précise de l'utilisateur, parcourir une série de données, etc.
Une boucle s'exécute tant qu'une condition est remplie. Nous réutiliserons donc des notions du chapitre précédent !
La boucle while
Pour décortiquer précisément ce qui se passe dans une boucle, nous allons voir comment elle se construit ! Une boucle commence par une déclaration : ici while
. Cela veut dire, à peu de chose près, « tant que ». Puis nous avons une condition : c'est elle qui permet à la boucle de s'arrêter. Une boucle n'est utile que lorsque nous pouvons la contrôler, et donc lui faire répéter une instruction un certain nombre de fois. C'est à ça que servent les conditions. Ensuite nous avons une ou plusieurs instructions : c'est ce que va répéter notre boucle (il peut même y avoir des boucles dans une boucle !
1 2 3 4 | while (/* Condition */) { //Instructions à répéter } |
Nous allons travailler sur un exemple concret mais d'abord, réfléchissons à « comment notre boucle va travailler ». Pour cela, il faut déterminer notre exemple.
Nous allons afficher « Bonjour, <un prénom> », prénom qu'il faudra taper au clavier ; puis nous demanderons si l'on veut recommencer. Pour cela, il nous faut une variable qui va recevoir le prénom, donc dont le type sera String
, ainsi qu'une variable pour récupérer la réponse. Et là, plusieurs choix s'offrent à nous : soit un caractère, soit une chaîne de caractères, soit un entier. Ici, nous prendrons une variable de type char
. C'est parti !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //Une variable vide String prenom; //On initialise celle-ci à O pour oui char reponse = 'O'; //Notre objet Scanner, n'oubliez pas l'import de java.util.Scanner ! Scanner sc = new Scanner(System.in); //Tant que la réponse donnée est égale à oui… while (reponse == 'O') { //On affiche une instruction System.out.println("Donnez un prénom : "); //On récupère le prénom saisi prenom = sc.nextLine(); //On affiche notre phrase avec le prénom System.out.println("Bonjour " +prenom+ ", comment vas-tu ?"); //On demande si la personne veut faire un autre essai System.out.println("Voulez-vous réessayer ? (O/N)"); //On récupère la réponse de l'utilisateur reponse = sc.nextLine().charAt(0); } System.out.println("Au revoir…"); //Fin de la boucle |
Vous avez dû cligner des yeux en lisant reponse = sc.nextLine().charAt(0);
. Rappelez-vous comment on récupère un char
avec l'objet Scanner
: nous devons récupérer un objet String
et ensuite prendre le premier caractère de celui-ci ! Eh bien cette syntaxe est une contraction de ce que je vous avais fait voir auparavant.
Détaillons un peu ce qu'il se passe. Dans un premier temps, nous avons déclaré et initialisé nos variables. Ensuite, la boucle évalue la condition qui nous dit : tant que la variable reponse
contient « O », on exécute la boucle. Celle-ci contient bien le caractère « O », donc nous entrons dans la boucle. Puis l'exécution des instructions suivant l'ordre dans lequel elles apparaissent dans la boucle a lieu. À la fin, c'est-à-dire à l'accolade fermante de la boucle, le compilateur nous ramène au début de la boucle.
Cette boucle n'est exécutée que lorsque la condition est remplie : ici, nous avons initialisé la variable reponse
à « O » pour que la boucle s'exécute. Si nous ne l'avions pas fait, nous n'y serions jamais entrés. Normal, puisque nous testons la condition avant d'entrer dans la boucle !
Voilà. C'est pas mal, mais il faudrait forcer l'utilisateur à ne taper que « O » ou « N ». Comment faire ? C'est très simple : avec une boucle ! Il suffit de forcer l'utilisateur à entrer soit « N » soit « O » avec un while
! Attention, il nous faudra réinitialiser la variable reponse
à « ' '
» (caractère vide). Il faudra donc répéter la phase « Voulez-vous réessayer ? » tant que la réponse donnée n'est pas « O » ou « N ».
Voici notre programme dans son intégralité :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | String prenom; char reponse = 'O'; Scanner sc = new Scanner(System.in); while (reponse == 'O') { System.out.println("Donnez un prénom : "); prenom = sc.nextLine(); System.out.println("Bonjour " +prenom+ ", comment vas-tu ?"); //Sans ça, nous n'entrerions pas dans la deuxième boucle reponse = ' '; //Tant que la réponse n'est pas O ou N, on repose la question while(reponse != 'O' && reponse != 'N') { //On demande si la personne veut faire un autre essai System.out.println("Voulez-vous réessayer ? (O/N)"); reponse = sc.nextLine().charAt(0); } } System.out.println("Au revoir…"); |
Vous pouvez tester ce code (c'est d'ailleurs vivement conseillé) : vous verrez que si vous n'entrez pas la bonne lettre, le programme vous posera sans cesse sa question, comme à la figure suivante !
Attention à écrire correctement vos conditions et à bien vérifier vos variables dans vos while
, et dans toutes vos boucles en général. Sinon c'est le drame ! Essayez d'exécuter le programme précédent sans la réinitialisation de la variable reponse
, et vous verrez le résultat ! On n'entre jamais dans la deuxième boucle, car reponse = 'O'
(puisque initialisée ainsi au début du programme). Là, vous ne pourrez jamais changer sa valeur… Le programme ne s'arrêtera donc jamais ! On appelle ça une « boucle infinie ». En voici un autre exemple.
1 2 3 4 5 | int a = 1, b = 15; while (a < b) { System.out.println("coucou " +a+ " fois !!"); } |
Si vous lancez ce programme, vous allez voir une quantité astronomique de « coucou 1 fois !! ». Nous aurions dû ajouter une instruction dans le bloc d'instructions de notre while
pour changer la valeur de a
à chaque tour de boucle, comme ceci :
1 2 3 4 5 6 | int a = 1, b = 15; while (a < b) { System.out.println("coucou " +a+ " fois !!"); a++; } |
Ce qui nous donnerait comme résultat la figure suivante :
Une petite astuce : lorsque vous n'avez qu'une instruction dans votre boucle, vous pouvez enlever les accolades, car elles deviennent superflues, tout comme pour les instructions if
, else if
ou else
.
Vous auriez aussi pu utiliser cette syntaxe :
1 2 3 | int a = 1, b = 15; while (a++ < b) System.out.println("coucou " +a+ " fois !!"); |
Souvenez-vous de ce dont je vous parlais au chapitre précédent sur la priorité des opérateurs. Ici, l'opérateur « < » a la priorité sur l'opérateur d'incrémentation « ++ ». Pour faire court, la boucle while
teste la condition et ensuite incrémente la variable a
. Par contre, essayez ce code :
1 2 3 | int a = 1, b = 15; while (++a < b) System.out.println("coucou " +a+ " fois !!"); |
Vous devez remarquer qu'il y a un tour de boucle en moins ! Eh bien avec cette syntaxe, l'opérateur d'incrémentation est prioritaire sur l'opérateur d'inégalité (ou d'égalité), c'est-à-dire que la boucle incrémente la variable a
, et ce n'est qu'après l'avoir fait qu'elle teste la condition !
La boucle do… while
Puisque je viens de vous expliquer comment fonctionne une boucle while
, je ne vais pas vraiment m'attarder sur la boucle do… while
. En effet, ces deux boucles ne sont pas cousines, mais plutôt sœurs. Leur fonctionnement est identique à deux détails près.
1 2 3 | do{ //Instructions }while(a < b); |
Première différence
La boucle do… while
s'exécutera au moins une fois, contrairement à sa sœur. C'est-à-dire que la phase de test de la condition se fait à la fin, car la condition se met après le while
.
Deuxième différence
C'est une différence de syntaxe, qui se situe après la condition du while
. Vous voyez la différence ? Oui ? Non ? Il y a un « ;
» après le while
. C'est tout ! Ne l'oubliez cependant pas, sinon le programme ne compilera pas.
Mis à part ces deux éléments, ces boucles fonctionnent exactement de la même manière. D'ailleurs, refaisons notre programme précédent avec une boucle do… while
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | String prenom = new String(); //Pas besoin d'initialiser : on entre au moins une fois dans la boucle ! char reponse = ' '; Scanner sc = new Scanner(System.in); do{ System.out.println("Donnez un prénom : "); prenom = sc.nextLine(); System.out.println("Bonjour " +prenom+ ", comment vas-tu ?"); do{ System.out.println("Voulez-vous réessayer ? (O/N)"); reponse = sc.nextLine().charAt(0); }while(reponse != 'O' && reponse != 'N'); }while (reponse == 'O'); System.out.println("Au revoir…"); |
Vous voyez donc que ce code ressemble beaucoup à celui utilisé avec la boucle while
, mais il comporte une petite subtilité : ici, plus besoin de réinitialiser la variable reponse
, puisque de toute manière, la boucle s'exécutera au moins une fois !
La boucle for
Cette boucle est un peu particulière puisqu'elle prend tous ses attributs dans sa condition et agit en conséquence. Je m'explique : jusqu'ici, nous avions fait des boucles avec :
- déclaration d'une variable avant la boucle ;
- initialisation de cette variable ;
- incrémentation de celle-ci dans la boucle.
Eh bien on met tout ça dans la condition de la boucle for
, et c'est tout. Il existe une autre syntaxe pour la boucle for
depuis le JDK 1.5. Nous la verrons lorsque nous aborderons les tableaux. Mais je sais bien qu'un long discours ne vaut pas un exemple, alors voici une boucle for
sous vos yeux ébahis :
1 2 3 4 | for(int i = 1; i <= 10; i++) { System.out.println("Voici la ligne "+i); } |
Ce qui donne la figure suivante :
Vous aurez sûrement remarqué la présence des « ;
» dans la condition pour la séparation des champs. Ne les oubliez surtout pas, sinon le programme ne compilera pas.
Nous pouvons aussi inverser le sens de la boucle, c'est-à-dire qu'au lieu de partir de 0 pour aller à 10, nous allons commencer à 10 pour atteindre 0 :
1 2 | for(int i = 10; i >= 0; i--) System.out.println("Il reste "+i+" ligne(s) à écrire"); |
On obtient la figure suivante :
Pour simplifier, la boucle for
est un peu le condensé d'une boucle while
dont le nombre de tours se détermine via un incrément. Nous avons un nombre de départ, une condition qui doit être remplie pour exécuter une nouvelle fois la boucle et une instruction de fin de boucle qui incrémente notre nombre de départ. Remarquez que rien ne nous empêche de cumuler les déclarations, les conditions et les instructions de fin de boucle :
1 2 3 | for(int i = 0, j = 2; (i < 10 && j < 6); i++, j+=2){ System.out.println("i = " + i + ", j = " + j); } |
Ici, cette boucle n'effectuera que deux tours puisque la condition (i < 10 && j < 6)
est remplie dès le deuxième tour, la variable j
commençant à 2 et étant incrémentée de deux à chaque tour de boucle.
- Les boucles vous permettent simplement d'effectuer des tâches répétitives.
- Il existe plusieurs sortes de boucles :
- la boucle
while(condition){…}
évalue la condition puis exécute éventuellement un tour de boucle (ou plus) ; - la boucle
do{…}while(condition);
fonctionne exactement comme la précédente, mais effectue un tour de boucle quoi qu'il arrive ; - la boucle
for
permet d'initialiser un compteur, une condition et un incrément dans sa déclaration afin de répéter un morceau de code un nombre limité de fois.
- la boucle
- Tout comme les conditions, si une boucle contient plus d'une ligne de code à exécuter, vous devez l'entourer d'accolades afin de bien en délimiter le début et la fin.