Nous abordons ici l'un des chapitres les plus importants : les conditions sont une autre notion fondamentale de la programmation. En effet, ce qui va être développé ici s'applique à énormément de langages de programmation, et pas seulement à Java.
Dans une classe, la lecture et l'exécution se font de façon séquentielle, c'est-à-dire ligne par ligne. Avec les conditions, nous allons pouvoir gérer différents cas de figure sans pour autant lire tout le code. Vous vous rendrez vite compte que tous vos projets ne sont que des enchaînements et des imbrications de conditions et de boucles (notion que l'on abordera au chapitre suivant).
Assez de belles paroles ! Entrons tout de suite dans le vif du sujet.
La structure if… else
Avant de pouvoir créer et évaluer des conditions, vous devez savoir que pour y parvenir, nous allons utiliser ce qu'on appelle des « opérateurs logiques ». Ceux-ci sont surtout utilisés lors de conditions (si [test] alors [faire ceci]) pour évaluer différents cas possibles. Voici les différents opérateurs à connaître :
- « == » : permet de tester l'égalité.
- « != » : permet de tester l’inégalité.
- « < » : strictement inférieur.
- « <= » : inférieur ou égal.
- « > » : strictement supérieur.
- « >= » : supérieur ou égal.
- « && » : l'opérateur
ET
. Il permet de préciser une condition - « || » : le
OU
. Même combat que le précédent. - « ? : » : l'opérateur ternaire. Pour celui-ci, vous comprendrez mieux avec un exemple qui sera donné vers la fin de ce chapitre.
Comme je vous l'ai dit dans le chapitre précédent, les opérations en Java sont soumises à des priorités. Tous ces opérateurs se plient à cette règle, de la même manière que les opérateurs arithmétiques…
Imaginons un programme qui demande à un utilisateur d'entrer un nombre entier relatif (qui peut être soit négatif, soit nul, soit positif). Les structures conditionnelles vont nous permettre de gérer ces trois cas de figure. La structure de ces conditions ressemble à ça :
1 2 3 4 5 6 7 8 | if(//condition) { //Exécution des instructions si la condition est remplie } else { //Exécution des instructions si la condition n'est pas remplie } |
Cela peut se traduire par « si… sinon… ».
Le résultat de l'expression évaluée par l'instruction if
sera un boolean
, donc soit true
, soit false
. La portion de code du bloc if
ne sera exécutée que si la condition est remplie. Dans le cas contraire, c'est le bloc de l'instruction else
qui le sera. Mettons notre petit exemple en pratique :
1 2 3 4 5 6 | int i = 10; if (i < 0) System.out.println("le nombre est négatif"); else System.out.println("le nombre est positif"); |
Essayez ce petit code, et vous verrez comment il fonctionne. Dans ce cas, notre classe affiche « le nombre est positif ». Expliquons un peu ce qui se passe.
- Dans un premier temps, la condition du
if
est testée : elle dit « sii
est strictement inférieur à 0 alors fais ça ». - Dans un second temps, vu que la condition précédente est fausse, le programme exécute le
else
.
Attends un peu ! Lorsque tu nous as présenté la structure des conditions, tu as mis des accolades et là, tu n'en mets pas. Pourquoi ?
Bien observé. En fait, les accolades sont présentes dans la structure « normale » des conditions, mais lorsque le code à l'intérieur de l'une d'entre elles n'est composé que d'une seule ligne, les accolades deviennent facultatives.
Comme nous avons l'esprit perfectionniste, nous voulons que notre programme affiche « le nombre est nul » lorsque i
est égal à 0 ; nous allons donc ajouter une condition. Comment faire ? La condition du if
est remplie si le nombre est strictement négatif, ce qui n'est pas le cas ici puisque nous allons le mettre à 0. Le code contenu dans la clause else
est donc exécuté si le nombre est égal ou strictement supérieur à 0. Il nous suffit d'ajouter une condition à l'intérieur de la clause else
, comme ceci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int i = 0; if (i < 0) { System.out.println("Ce nombre est négatif !"); } else { if(i == 0) System.out.println("Ce nombre est nul !"); else System.out.println("Ce nombre est positif !"); } |
Maintenant que vous avez tout compris, je vais vous présenter une autre façon d'écrire ce code, avec le même résultat : on ajoute juste un petit « sinon si… ».
1 2 3 4 5 6 7 8 9 | int i = 0; if (i < 0) System.out.println("Ce nombre est négatif !"); else if(i > 0) System.out.println("Ce nombre est positif !"); else System.out.println("Ce nombre est nul !"); |
Alors ? Explicite, n'est-ce pas ?
- si
i
est strictement négatif alors le code de cette condition est exécuté. - sinon si
i
est strictement positif alors le code de cette condition est exécuté. - sinon
i
est forcément nul alors le code de cette condition est exécuté.
Il faut absolument donner une condition au else if
pour qu'il fonctionne.
Ici, je vais très fortement insister sur un point : regardez l'affichage du code et remarquez le petit décalage entre le test et le code à exécuter. On appelle cela l'indentation !
Pour vous repérer dans vos futurs programmes, cela sera très utile. Imaginez deux secondes que vous avez un programme de 700 lignes avec 150 conditions, et que tout est écrit le long du bord gauche. Il sera difficile de distinguer les tests du code. Vous n'êtes pas obligés de le faire, mais je vous assure que vous y viendrez.
Avant de passer à la suite, vous devez savoir qu'on ne peut pas tester l'égalité de chaînes de caractères ! Du moins, pas comme je vous l'ai montré ci-dessus. Nous aborderons ce point plus tard.
Les conditions multiples
Derrière ce nom barbare se cachent simplement plusieurs tests dans une instruction if
(ou else if
). Nous allons maintenant utiliser les opérateurs logiques que nous avons vus au début en vérifiant si un nombre donné appartient à un intervalle connu. Par exemple, on va vérifier si un entier est compris entre 50 et 100.
1 2 3 4 5 | int i = 58; if(i < 100 && i > 50) System.out.println("Le nombre est bien dans l'intervalle."); else System.out.println("Le nombre n'est pas dans l'intervalle."); |
Nous avons utilisé l'opérateur &&
. La condition de notre if
est devenue : « si i
est inférieur à 100 ET
supérieur à 50 ».
Avec l'opérateur « && », la clause est remplie si et seulement si les conditions la constituant sont toutes remplies ; si l'une des conditions n'est pas vérifiée, la clause sera considérée comme fausse.
Cet opérateur vous initie à la notion d'intersection d'ensembles. Ici, nous avons deux conditions qui définissent un ensemble chacune :
i < 100
définit l'ensemble des nombres inférieurs à 100 ;i > 50
définit l'ensemble des nombres supérieurs à 50.
L'opérateur « && » permet de faire l'intersection de ces ensembles. La condition regroupe donc les nombres qui appartiennent à ces deux ensembles, c’est-à-dire les nombres de 51 à 99 inclus. Réfléchissez bien à l'intervalle que vous voulez définir. Voyez ce code :
1 2 3 4 5 | int i = 58; if(i < 100 && i > 100) System.out.println("Le nombre est bien dans l'intervalle."); else System.out.println("Le nombre n'est pas dans l'intervalle."); |
Ici, la condition ne sera jamais remplie, car je ne connais aucun nombre qui soit à la fois plus petit et plus grand que 100 ! Reprenez le code précédent et remplacez l'opérateur « && » par « || » (petit rappel, il s'agit du OU
). À l'exécution du programme et après plusieurs tests de valeur pour i
, vous pourrez vous apercevoir que tous les nombres remplissent cette condition, sauf 100.
La structure switch
Le switch
est surtout utilisé lorsque nous voulons des conditions « à la carte ». Prenons l'exemple d'une interrogation comportant deux questions. Pour chacune d'elles, on peut obtenir uniquement 0 ou 10 points, ce qui nous donne au final trois notes et donc trois appréciations possibles, comme ceci :
- 0/20 : tu dois revoir ce chapitre !
- 10/20 : je crois que tu as compris l'essentiel ! Viens relire ce chapitre à l'occasion.
- 20/20 : bravo !
Dans ce genre de cas, on utilise un switch
pour éviter des else if
à répétition et pour alléger un peu le code. Je vais vous montrer comment se construit une instruction switch
; puis nous allons l'utiliser tout de suite après.
Syntaxe
1 2 3 4 5 6 7 8 | switch (/*Variable*/) { case /*Argument*/: /*Action*/; break; default: /*Action*/; } |
Voici les opérations qu'effectue cette expression :
- La classe évalue l'expression figurant après le
switch
(ici/*Variable*/
). - Si la première languette (
case /*Valeur possible de la variable*/:
) correspond à la valeur de/*Variable*/
, l'instruction figurant dans celle-ci sera exécutée. - Sinon, on passe à la languette suivante, et ainsi de suite.
- Si aucun des cas ne correspond, la classe va exécuter ce qui se trouve dans l'instruction
default:/*Action*/;
. Voyez ceci comme une sécurité.
Notez bien la présence de l'instruction break;
. Elle permet de sortir du switch
si une languette correspond. Pour mieux juger de l'utilité de cette instruction, enlevez tous les break;
et compilez votre programme. Vous verrez le résultat… Voici un exemple de switch
que vous pouvez essayer :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | int note = 10; //On imagine que la note maximale est 20 switch (note) { case 0: System.out.println("Ouch !"); break; case 10: System.out.println("Vous avez juste la moyenne."); break; case 20: System.out.println("Parfait !"); break; default: System.out.println("Il faut davantage travailler."); } |
Je n'ai écrit qu'une ligne de code par instruction case
, mais rien ne vous empêche d'en mettre plusieurs.
Si vous avez essayé ce programme en supprimant l'instruction break;
, vous avez dû vous rendre compte que le switch
exécute le code contenu dans le case 10:
, mais aussi dans tous ceux qui suivent ! L'instruction break;
permet de sortir de l'opération en cours. Dans notre cas, on sort de l'instruction switch
, mais nous verrons une autre utilité à break;
dans le chapitre suivant.
Depuis la version 7 de Java, l'instruction switch
accepte les objets de type String
en paramètre. De ce fait, cette instruction est donc valide :
1 2 3 4 5 6 7 8 9 10 11 12 | String chaine = "Bonjour"; switch(chaine) { case "Bonjour": System.out.println("Bonjour monsieur !"); break; case "Bonsoir": System.out.println("Bonsoir monsieur !"); break; default: System.out.println("Bonjoir ! :p"); } |
La condition ternaire
Les conditions ternaires sont assez complexes et relativement peu utilisées. Je vous les présente ici à titre indicatif. La particularité de ces conditions réside dans le fait que trois opérandes (c'est-à-dire des variables ou des constantes) sont mis en jeu, mais aussi que ces conditions sont employées pour affecter des données à une variable. Voici à quoi ressemble la structure de ce type de condition :
1 2 | int x = 10, y = 20; int max = (x < y) ? y : x ; //Maintenant, max vaut 20 |
Décortiquons ce qu'il se passe :
- Nous cherchons à affecter une valeur à notre variable
max
, mais de l'autre côté de l'opérateur d'affectation se trouve une condition ternaire… - Ce qui se trouve entre les parenthèses est évalué :
x
est-il plus petit quey
? Donc, deux cas de figure se profilent à l'horizon :- si la condition renvoie
true
(vrai), qu'elle est vérifiée, la valeur qui se trouve après le?
sera affectée ; - sinon, la valeur se trouvant après le symbole
:
sera affectée.
- si la condition renvoie
- L'affectation est effective : vous pouvez utiliser votre variable
max
.
Vous pouvez également faire des calculs (par exemple) avant d'affecter les valeurs :
1 2 | int x = 10, y = 20; int max = (x < y) ? y * 2 : x * 2 ; //Ici, max vaut 2 * 20 donc 40 |
N'oubliez pas que la valeur que vous allez affecter à votre variable doit être du même type que votre variable. Sachez aussi que rien ne vous empêche d'insérer une condition ternaire dans une autre condition ternaire :
1 2 3 4 5 6 7 8 | int x = 10, y = 20; int max = (x < y) ? (y < 10) ? y % 10 : y * 2 : x ; //Max vaut 40 //Pas très facile à lire… //Vous pouvez entourer votre deuxième instruction ternaire par des parenthèses pour mieux voir : max = (x < y) ? ((y < 10) ? y % 10 : y * 2) : x ; //Max vaut 40 |
- Les conditions vous permettent de n'exécuter que certains morceaux de code.
- Il existe plusieurs sortes de structures conditionnelles :
- la structure
if... elseif... else
; - la structure
switch... case... default
; - la structure
? :
.
- la structure
- Si un bloc d'instructions contient plus d'une ligne, vous devez l'entourer d'accolades afin de bien en délimiter le début et la fin.
- Pour pouvoir mettre une condition en place, vous devez comparer des variables à l'aide d'opérateurs logiques.
- Vous pouvez mettre autant de comparaisons renvoyant un
boolean
que vous le souhaitez dans une condition. - Pour la structure
switch
, pensez à mettre les instructionsbreak;
si vous ne souhaitez exécuter qu'un seul bloccase
.