ICS3U

Accueil > Programmer avec Java > Structures de contrôle >

📚 Boucles

Survol et attentes

Définitions

La répétition conditionnelle d’un bloc de code est un autre concept fondamental de la programmation. Elle permet aux programmes de devenir puissants en profitant de la vitesse d’exécution de l’ordinateur et prévient la répétition de code.

La boucle while est la plus polyvalente et peut servir à tous les contextes. La boucle for est plus spécialisée et est utilisée pour traiter une suite de nombres.

boucle
une structure de contrôle qui répète un bloc de code tant qu’une condition est vraie.

itération une seule exécution du bloc de code dans une boucle.

mécanisme de mise à jour
combinaison de variables et d’instructions qui ont l’objectif d’amener la condition de la boucle à false et prévenir les boucles infinies.
variable de contrôle
une variable qui est utilisée pour contrôler la condition de la boucle.
variable accumulateur
variable qu’on déclare avant une boucle qui collecte des valeurs pendant les itérations de la boucle, comme une somme ou une liste de noms.
drapeau booléen
une variable booléenne utilisé pour représenter l’état de quelque chose. Dans ce contexte, un drapeau booléen peut remplacer la condition de la boucle et sa valeur peut être modifiée à l’intérieur du bloc de code.
break
mot-clé Java qui force la sortie d’une boucle, peu importe la condition ou la position dans le bloc de code.
continue
mot-clé Java qui force la boucle à passer à l’itération suivante, ignorant toutes les instructions restantes dans le bloc de code.

Objectifs d’apprentissage

À la fin de cette leçon vous devrez être en mesure de :

Critères de succès

Boucle while

Voici la syntaxe de base pour une boucle while :

1
2
3
4
while (condition) {
    // bloc de code
    // mécanisme de mise à jour
}

boucle

C’est important de noter que l’exécution des instructions ne continue pas après le bloc de code mais revient à la condition. C’est ça qui forme la boucle. Si la condition est true, le bloc de code est répété. Si la condition est false, l’exécution continue après la boucle. Ici, le diagramme de flux donne une meilleure représentation de l’exécution réelle de étapes.

Exemple : Traiter une suite de nombres

Pour traiter une suite de nombres, on définit d’abord une variable de contrôle qui représente la valeur initiale de la suite. Ensuite, on définit la condition de la boucle en fonction de cette variable de contrôle. Finalement, on met à jour la variable de contrôle à l’intérieur du bloc de code.

Placez le code suivant dans un fichier qui s’appelle LoopExamples1.java et exécutez-le pour voir les résultats.

Par exemple, pour afficher les nombres de 1 à 10 :

Avec while

1
2
3
4
5
6
7
8
9
10
11
void whileLoop() {
    int i = 1;          // initialiser la variable de contrôle
    while (i <= 10) {   // condition utilisant la variable de contrôle
        System.out.println(i);
        i++; // mise à jour de la variable de contrôle (incrémenter)
    }
}

void main() {
    whileLoop();
}

boucle while 1

L'exécution du code précédent commence à quelle ligne?

La ligne 9, à la signature de main. La ligne 10 envoie ensuite l’exécution à la ligne 1 en appelant whileLoop().

Combien de fois est-ce que la ligne 2 sera-t-elle exécutée?

Une seule fois. Elle vient juste avant le début de la déclaration while.

Combien de fois est-ce que la ligne 4 sera-t-elle exécutée?

Dix fois : une pour chaque valeur de i qui donne un résultat true à i <= 10

Combien de fois est-ce que la ligne 3 sera-t-elle exécutée?

11 fois! Oui, on doit aussi visiter la condition pour la fois que la condition est fausse, quand i est égale à 11, brisant la boucle. La condition est donc évaluée une fois de plus que le nombre d’itération.

Quelle sera la sortie du code précédant?

La sortie est :

1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10

Avec for

La boucle for est spécialisée pour ce type de tâche. Elle inclut les trois éléments clés de la boucle directement dans sa déclaration. Sa syntaxe est la suivante :

1
2
3
for (initialisation; condition; mise à jour) {
    // bloc de code
}

Par exemple, pour afficher les nombres de 1 à 10 avec une boucle for :

1
2
3
4
5
void forLoop() {
    for (int i = 1; i <= 10; i++) { // les trois éléments séparés par des ;
        System.out.println(i);
    }
}

Si on appelle aussi cette méthode dans main, on aura exactement la même sortie qu’avec la version while. Ajoutez-le à votre fichier LoopExamples1.java pour le vérifier.

Défi

Pouvez vous trouver et afficher la somme de toutes les valeurs de 1 à 10 en modifiant une des boucles ci-dessus?

Indice : vous aurez besoin d’une variable accumulateur en plus de la variable de contrôle.

Exemple : Valider des données d’entrée

Un autre contexte pour une boucle est demander une réponse à l’utilisateur tant que la réponse n’est pas valide.

Une situation typique est lorsqu’on demande une confirmation oui/non à l’utilisateur. On peut utiliser une boucle while pour s’assurer que la réponse est valide.

Voici deux façons de le faire. Il en existe d’autres! Vous pouvez tester ces méthodes dans un nouveau fichier LoopExamples2.java.

Avec une variable de contrôle pour la condition de la boucle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.*;

final Scanner INPUT = new Scanner(System.in);

String again() {
    String answer = ""; // variable : contrôle ET accumulateur

    while (!(answer.equals("oui") || answer.equals("non"))) { 
        System.out.print("Voulez-vous continuer? (oui/non) > ");
        answer = INPUT.next().toLowerCase();
            // mise à jour avec une réponse en minuscules
    }
    return answer;
}

void main() {
    while (again().equals("oui")) {
        // code à répéter
    }
    System.out.println("Au revoir");
}

boucle while 2

Il y a deux conditions dans ce code.

Le plus complexe est dans again() : !(answer.equals("oui") || answer.equals("non")) :

  • Le ! au début indique qu’on veut inverser le résultat entre les parenthèses - c’est parce que ce qu’on décrit entre parenthèses correspond à ce que nous voulons, mais la boucle devrait se répéter dans le cas contraire
  • Le || est l’opérateur “ou” qui sera vrai si l’une ou l’autre des conditions est vraie.
  • On utilise .equals() pour comparer l’égalité parce qu’on compare deux String.

Plaçant tout ça ensemble avec le mot-clé while, on devrait lire :

1
si la réponse EST "oui" OU "non", NE PAS répéter le bloc de code

La deuxième condition est dans main : again().equals("oui") :

  • again retourne un String au programme qui est directement utilisé dans la comparaison

Voici un exemple d’interaction avec l’utilisateur pour ce programme :

1
2
3
4
Voulez-vous continuer? (oui/non) > peut-être
Voulez-vous continuer? (oui/non) > n
Voulez-vous continuer? (oui/non) > Non
Au revoir
Combien des fois est-que la condition de la boucle dans la méthode again() est-elle évaluée durant l'intéraction ci-dessus?

4 fois : une au début avec la valeur initiale de "" et une pour chaque réponse de l’utilisateur

Pourquoi est-ce que la réponse "Non" a-t-elle été acceptée?

INPUT.next() nous donne "Non" ce qui ne serait pas equals à "non". Mais ce n’est pas ce qui se rend à la condition : on passe la réponse brute à la méthode toLowerCase() qui convertit tout en minuscules. Ainsi, answer contient la valeur "non" ce qui permet à la condition d’être vraie.

Défi

La condition pour évaluer si la réponse était invalide (alors répéter la boucle) est la suivante :

!(answer.equals("oui") || answer.equals("non")) = si la réponse EST "oui" OU "non", NE PAS répéter le bloc de code

On peut écrire cette même condition d’une autre façon.

Quelle condition serait équivalente à "répéter la boucle si la réponse n'EST PAS "oui" ET la réponse n'EST PAS "non"?

!answer.equals("oui") && !answer.equals("non")

Exemple : Répéter un programme jusqu’à ce que l’utilisateur décide de le quitter

Un autre contexte commun est une boucle de programme intentionellement infinie. Pour ces cas, la déclaration de la boucle est while (true). C’est ce qui se passe avec les fenêtres de vos applications : l’affichage est rafraîchi en permanence jusqu’à ce que vous fermiez la fenêtre.

Mais comment quitter une boucle où la condition de boucle est une constante? Réponse : on utilise une instruction break à l’intérieur du bloc de code. L’instruction break est insérée dans une sélection qui évalue si la condition de sortie est atteinte.

1
2
3
4
5
6
while (true) { // passe tout droit
    // bloc de code
    if (condition) {
        break; // sortie de la boucle
    }
}

infinite_loop

Notez que dans le diagramme pour une boucle while (true) la condition de boucle se trouve à l’intérieur et parfois à la fin des instructions de la boucle. Le “while (true)” n’est pas représenté directement parce que ça n’affecte pas le flux des étapes.

Notez que le mot-clé while n’apparaît jamais dans ces diagrammes, ni les autres mot-clés (p. ex.: if, else, true, break). Il s’agit simplement de conditions et d’embranchements dans les diagrammes. Dans les divers cas d’itération, une des branches forme une boucle. Sinon on parle de sélection / d’embranchement tout court.

Retour sur la validation de données

On pourrait remplacer la version de main dans LoopExamples2.java avec la version suivante :

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() {
    while (true) {
        // code de la tâche

        // code pour demander à l'utilisateur s'il veut continuer

        if (again().equals("non")) {
            break; // sortie de la boucle
        } else {
            // code pour réinitialiser les variables de la tâche
        }
    }
}

Pour d’autres tâches

Un autre exemple est pour faire la somme d’une série de nombres. On demande à l’utilisateur d’entrer un nombre à la fois. Si le nombre est -999, on quitte la boucle. Sinon, on ajoute le nombre à la somme.

Reprendre cet exemple dans un nouveau fichier LoopExamples3.java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.*;

void main() {
    Scanner input = new Scanner(System.in);

    int sum = 0; // variable accumulateur

    while (true) {
        System.out.print(
            "Entrez un nombre entier (-999 pour quitter) : "
        );
        
        int num = input.nextInt(); // variable de contrôle
        if (num == -999) {
            break; // mot-clé pour quitter la boucle
        } else {
            sum += num;
        }
    }
    System.out.println("La somme est " + sum);
}

while avec break

Et voici deux exemples d’interaction avec l’utilisateur :

1
2
3
4
5
Entrez un nombre entier (-999 pour quitter) : 5
Entrez un nombre entier (-999 pour quitter) : 10
Entrez un nombre entier (-999 pour quitter) : 15
Entrez un nombre entier (-999 pour quitter) : -999
La somme est 30
1
2
3
4
5
6
Entrez un nombre entier (-999 pour quitter) : -3
Entrez un nombre entier (-999 pour quitter) : 0
Entrez un nombre entier (-999 pour quitter) : 3
Entrez un nombre entier (-999 pour quitter) : 6
Entrez un nombre entier (-999 pour quitter) : -999
La somme est 6

Exercices

Pratique

Travaillez dans le répertoire GitHub partagé par votre enseignant pour la pratique et les exercices.

Contexte

Voici un autre exemple qui nous donne la partie entière du logarithme d’une valeur x en base 2. On divise x jusqu’à ce que sa valeur soit inférieure à 1. Le nombre de divisions est le logarithme de x en base 2.

1
2
3
4
5
6
7
8
9
int x = 1024; // valeur à traiter; aussi la variable de contrôle
System.out.print("Le log2 de " + x + " est ");

int divCounter = 0;
while (x > 1) { // condition
    divCounter++;
    x = x/2; // mise à jour (divise par 2)
}
System.out.println(divCounter);

et sa sortie:

1
Le log2 de 1024 est 10

Problème à résoudre

Écrire une boucle while (ou for) qui utilise une mise à jour autre que l’incrémentation. Par exemple, on peut utiliser une décrémentation, une multiplication ou une division, ou n’importe quel calcul que vous souhaitez en autant que la variable de contrôle se rapproche de la condition false à chaque itération. L’exemple précédant pour le logarithme utilise une division.