• Aucun résultat trouvé

Les structures de contrôle

Utilité

Les structures de contrôle existent dans de nombreux langages. Les langages OO n’y échappent pas en ce sens que la création d’objets et la communication entre ces derniers n’exclut pas la possibilité d’écrire des algorithmes. Nous nous contenterons ici de les énoncer, en vrac et pour information, sachant que les lecteurs de ces notes ont connaissance certaines généralités concernant ces structures56.

Les structures alternatives

Alternative simple

On retrouve en Java, comme dans de nombreux langages, le bon vieux “si... alors...sinon...” Sa syntaxe est la suivante:

if(expression_booléenne) { bloc_de_traitement1 } else{ bloc_de_traitement2 }

Les remarques principales concernent la condition qui est évidemment une expression booléenne devant se trouver entre parenthèses, le caractère optionnel de la partie else et le fait que les traitements à effectuer dans l’un ou dans l’autre cas sont regroupées dans un bloc57.

if (p1.equals(p2)){

System.out.println("Ces deux points ne définissent pas une droite!"); }

else{

Droite d = new Droite(p1,p2);

System.out.println("La droite d a pour équation: ", d); }

L’écriture de la condition peut faire intervenir des variables de types primitifs, des objets, des invocations de méthode et, bien entendu, des opérateurs en tous genres.

Alternative multiple

Il convient de faire une remarque à propos de cette structure. Elle concerne la manière dont l’analyse d’un problème logiciel est menée. Il est clair que les observations faites dans le chapitre précédent concernant l’héritage et surtout le polymorphisme, pousseront souvent les développeurs d’applications à envisager une hiérarchie de classes d’objets avec une spécialisation des méthodes au niveau des sous- classes. Dès lors, le polymorphisme aidant, la structure dont il est question ici s’avère inutile. A un choix multiple, se substitue la résolution de la surcharge et la recherche de la méthode possédant une signature convenable. Toutefois, la nécessité d’employer une structure avec alternative multiple n’exige pas toujours le passage par une hiérarchie de classes. C’est au programmeur d’en juger.

La syntaxe de cette structure est la suivante:

switch (valeur_entière){ case valeur1: bloc_de_traitement1 case valeur2: bloc_de_traitement2 ... default: bloc_de_traitement_par_défaut }

Quelques remarques importantes sont à faire:

• le paramètre à fournir à la structure switch doit correspondre à une expression ayant une valeur entière;

• si la valeur de cette expression ne se trouve pas dans les valeurs mentionnées, c’est le traitement par défaut qui est réalisé;

• s’il n’y a pas de traitement par défaut et que la valeur n’est pas rencontrée, la structure est simplement ignorée;

• la plupart des blocs de traitement doivent se terminer par l’instruction break; qui assure que les autres possibilités ne sont pas examinées;

58

Il vous est loisible d’améliorer la classe Clavier en y ajoutant une méthode lireChar().

Voici, à titre d’illustration, un petit programme qui affiche la valeur décimale d’un caractère (supposé être) hexadécimal. Le programme saisit le caractère sous forme d’une chaîne58 et affiche un message

s’il n’y a pas ou plus d’un caractère.

public class HexaVersDeci{

public static void main(String [] args){ String car = Clavier.lireString(); if (car.length()!=1){

System.out.println("ERREUR: un seul caractère"); }

else{

char c=car.charAt(0); int val=deci(c);

if(val!=-1){

System.out.println("Valeur du caractère:" + val); }

} }

public static int deci(char c){ switch(c){

case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':

return c-'0';

case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':

return c-'A'+10;

case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':

return c-'a'+10; default:

System.out.println("Ce caractère n’est pas employé en\ hexadécimal");

return (-1); }

} }

La méthode main n’affiche la valeur du caractère que si celui-ci est valide. La chaîne (même si elle ne comprend qu’un seul caractère) doit être transformée en caractère par les vertus de la méthode charAt.

59

Ce nombre peut être déterminé par la connaissance d’une valeur initiale et d’une valeur finale.

60

Il faut espérer que le programmeur ne s’est pas arrangé pour que n tende vers l’infini.

Dans la structure switch, les cas semblables sont regroupés. Les opérations arithmétiques entre caractères donnent bien des entiers de type int (promotion). Les instructions return ont aussi l’effet de l’instruction break.

Vous pourrez modifier sans trop de peine la méthode main pour que le programme fonctionne lorsqu’une chaîne de plus d’un caractère est fournie. Il y a lieu, dans ce cas, de distinguer les messages: • “Vous n’avez pas fourni de caractère”

“Vous avez fourni plus d’un caractère. Seul le premier a été pris en compte.”

Les structures répétitives

On retrouve ici les trois structures classiques permettant d’effectuer un traitement tant qu’une

condition est vérifiée, jusqu’à ce qu’une condition soit vérifiée ou encore, un nombre connu59

de fois.

La boucle “while”

Les instructions contenues dans une telle boucle sont exécutées de 0 à n fois60. La valeur booléenne

de la condition peut en effet être false dès le départ ce qui fait que les instructions de la boucle sont ignorées. Voici la syntaxe:

while (expression_booléenne){

bloc_de_traitement

}

Un (très) petit exemple:

public class BoucleWhile{

public static void main(String [] args){ int i = 0; while (i++<8){ System.out.println("Bienvenue à la séance " + i + " du cours Java."); } } }

La boucle “do - while”

Le bloc d’instructions est exécuté au moins une fois puisque la condition n’est testée qu’en fin de boucle.

do

bloc_de_traitement

while (expression_booléenne);

Vous remarquerez que les instructions à l’intérieur d’une structure do - while constituent toujours un bloc. De même, l’expression while(expression_booléenne) est obligatoirement suivie d’un point- virgule.

Un exemple assez semblable au précédent:

public class BoucleDoWhile{

public static void main(String [] args){ int i = 1; do System.out.println("Bienvenue à la séance " + i + " du cours Java."); while (i++<8); } }

Notez encore que l’expression booléenne pouvait s’écrire ++i<=8.

La boucle “for”

Dans cette structure, sont à préciser, les valeurs initiale(s) et finale(s) de la (des) variable(s) à prendre en considération. En voici la syntaxe:

for (initialisations; expression_booléenne; incrémentations){

bloc_de_traitement

{

Et toujours le même exemple...

public class BoucleFor{

public static void main(String [] args){ for(int i=1;i<=8;++i){

System.out.println("Bienvenue à la séance " + i + " du cours Java.");

} }

}

Comme le laisse supposer la syntaxe, il est possible d’initialiser plusieurs variables et de préciser plusieurs incrémentations (au sens large). La méthode qui suit renvoie l’exposant de la plus grande puissance de 2 supérieure ou égale à un nombre donné (en paramètre).

public static int puissanceDeDeux(int valeur){ int exp;

for(exp=0, valeur-=1; valeur>0; exp++, valeur/=2){ }

return exp; }

}

Quelques commentaires sont nécessaires. A chaque passage dans la boucle, il faudra diviser par deux (division entière) et augmenter de 1 la valeur de l’exposant. Cette dernière devra être initialisée à 0 et la valeur à diviser, à la valeur fournie moins une unité pour assurer qu’il s’agit bien d’un nombre supérieur ou égal (si valeur vaut 2, il faudra deux divisions avant que v vaille 0, alors que l’exposant doit valoir 1).

Il y a donc deux instructions d’initialisation et deux instructions d’incrémentation (augmenter de 1, diviser par 2).

Il n’y a pas d’instruction dans le bloc. Ce n’est pas nécessaire puisqu’elles sont incluses dans la structure for. En revanche, l’absence d’accolades entraîne une erreur de compilation.

La variable exp ne peut être initialisée dans la boucle car elle est valeur de retour.

“break”, “label”, “continue” et autre “return”

De nombreux discours tentent, sans doute à raison, de pousser les programmeurs dans la voie d’une programmation structurée. Il arrive cependant parfois que l’on confonde recommandation et impératif. Lorsque plusieurs structures sont imbriquées, on souhaite parfois échapper à l’imbrication dans des cas spécifiques. Sans pour cela en faire une habitude, l’emploi des instructions qui suivent peut parfois s’avérer intéressant.

L’instruction break ne permet pas seulement de quitter une structure switch comme vu précédemment. Elle permet de quitter le bloc dans lequel elle est écrite. Elle interrompt ainsi le flux d’exécution. Interruption classique:

do

int revenus = Clavier.lireInt() ; if(revenus<100000)

break; ... while(...);

L’instruction peut être utilisée dans l’ensemble des structures qui viennent d’être présentées: if -else,

switch, while, do - while, for.

Lorsque plusieurs blocs sont imbriqués, il est possible de quitter un bloc plus externe que le bloc dans lequel se trouve l’instruction. Il suffit alors d’étiqueter ce bloc et d’utiliser cette étiquette à la suite de l’instruction break. L’étiquetage d’une instruction se fait de la manière suivante:

étiquette: instruction

Interruption labélisée:

taxation: do

int revenus = Clavier.lireInt() ; if(revenus<100000){ System.out.println("Pas de taxation"); break taxation; } ... while(...);

L’instruction continue dans une boucle permet également de modifier le flux d’exécution en renvoyant l’exécution à la fin de la boucle et donc à l’évaluation de la condition de poursuite ou d’arrêt.

Enfin, vous connaissez déjà l’instruction return utilisée pour renvoyer une valeur ou une référence d’objet à un appelant. Lorsqu’il n’y a pas de valeur de retour, l’instruction rend tout simplement la main à l’appelant, ce qui est également une façon de rompre le flux normal d’exécution du programme.

Exercices

Ex1 Construisez un type abstrait Ensemble implanté à partir d’une liste chaînée simple. Rappelons

qu’un ensemble est une liste non nécessairement ordonnée d’éléments de même type et qu’un même élément ne peut se retrouver plusieurs fois dans l’ensemble.

Il faudra notamment pouvoir créer un ensemble, ajouter un élément à l’ensemble, vérifier si un élément appartient à l’ensemble, obtenir le nombre d’éléments qui le composent.

Ex 2 Améliorez le programme de statistiques sur les lancers de dés en affichant un histogramme sous

forme d’étoiles (une étoile par x unités), comme par exemple: *

*** ****** ** *

Ex 3 Ecrivez une application qui prend en paramètres de la ligne de commande les coefficients a, b et

c d’un trinôme du second degré et qui affiche un message décrivant le nombre et la valeurs des racines éventuelles.

Ex 4 Ecrivez une application qui simule le lancer d’un dé et qui affiche le nombre de lancers qu’il a fallu:

• avant d’obtenir deux fois six consécutivement; • avant d’obtenir le résultat six après le résultat un.

Nous pourrions allonger indéfiniment la liste des exercices qui mettent en jeu les structures de contrôle disponibles en Java. Ces problèmes ne sont toutefois pas spécifiques à la POO. Tous les problèmes de cette nature traités habituellement avec les langages associés à la programmation impérative peuvent donc être repris ici, et en particulier, tous ceux qui ont pour objectif de remplir des tableaux, par exemple. Nous n’allons donc pas allonger la liste des exercices possibles de manière inconsidérée. Nous vous renvoyons, pour cela, à des ouvrages plus anciens mais toujours bien d’actualité pour ce qui est de mettre en place les concepts liés à la programmation classique.

61

Les classes d’héritage ne sont pas forcées d’implanter la méthode abstraite auquel cas elles restent abstraites. Ce sera alors à une des sous-classes de l’implanter.

Documents relatifs