Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Définition de blocs d'instructions

Synthèse sur les opérateurs Java Les instructions conditionnelles



Accès rapide :
La vidéo
Introduction à la notion d'instruction
Le bloc d'instructions
Les conventions de codage

La vidéo

Cette vidéo vous montre comment définir des blocs d'instructions en Java et comment ils permettent de contrôler la durée de vie de vos variables.


Définition de blocs d'instructions

Introduction à la notion d'instruction

en fait, pour les instructions, Java s'inspire très fortement de la syntaxe du langage C (nous en avons déjà parlé). Ceux d'entre vous qui connaissent déjà C reconnaitront donc beaucoup de choses, même si quelques divergences existent (assert, « for each », ...).

Dans les chapitres précédents, nous avons principalement étudié les types, les opérateurs et les expressions Java. La définition d'une expression est qu'elle calcule une valeur à partir des opérandes qui sont passés en paramètres. Parallèlement, nous avons commencé à parler des instructions (statements en anglais). Une instruction permettent de lancer des actions (un test, une boucle, une assertion, ...). Il est maintenant temps d'étudier plus précisément ces instructions.

Définir la notion d'instruction n'est pas si simple. D'autant que souvent les instructions Java sont constituées de sous-instructions et d'expressions. Une instruction simple doit se terminer par le caractère ; : attention, en Java le ; est un terminateur d'instructions et non pas un séparateur comme en Javascript. Cela veut dire que la dernière instruction d'un bloc doit elle aussi avoir ce dernier caractère. Voici un exemple de code comportant trois instructions simples dans une méthode main;

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
public class Demo {

    public static void main( String [] args ) {
    
        // Une première instruction simple (en fait un appel de méthode)
        System.out.println( "A statement" );
        
        // Une seconde instruction de type déclaration de variable 
        int i = 10;
    
        // Une dernière instruction de contrôle (ici une condition) 
        if ( i < 5 ) System.out.println( "C'est petit" );
        
    } 

}
Trois instructions dans un main

L'oublie d'un des trois ; de l'exemple ci-dessus produira une erreur de compilation.

$> javac Demo.java
Demo.java:12: error: ';' expected
        if ( i < 5 ) System.out.println( "C'est petit" )
                                                        ^
1 error
$>

Le bloc d'instructions

Comme son nom le laisse présager, le bloc d'instructions peut contenir plusieurs instructions (il peut aussi en contenir qu'une unique). Le bloc commence par une accolade ouvrante et se termine par une accolade fermante. L'exemple ci-dessous montre un bloc d'instructions vous demandant de saisir votre nom. La seconde instruction du bloc permet de capturer dans une variable de type chaîne de caractères, la valeur que vous aurez saisie à partir du clavier. Enfin, la troisième instruction permet d'afficher la valeur saisie sur la console. Notez bien que chaque instruction est terminée, comme nous venons de le dire précédemment par un point-virgule. Si vous ne respectez pas cette règle, une erreur de compilation vous sera retournée.

 1 
 2 
 3 
 4 
 5 
{
    System.out.print( "Veuillez renseigner votre nom : " );
    String nom = System.console().readline();
    System.out.println( "Votre nom est : " + nom );
}
Un exemple de bloc d'instructions
la méthode statique System.console() n'est disponible que depuis le Java SE 6.0. De plus, elle ne marche que et uniquement que si vous lancez le programme à partir d'une console shell. Si au contraire, vous lancer ce programme à partir de la console d'Eclipse, la valeur null vous sera retournée ce qui déclenchera une erreur lors de l'appel à readLine. C'est pour cette raison que dans les exemples précédents je n'en ai pas trop parlé.

Soyons clair, le main défini lui aussi un bloc d'instructions : effectivement, après la liste des paramètres on débute un bloc d'instructions via une accolade ouvrante. De plus vous pouvez placer un bloc d'instructions à l'intérieur d'un autre bloc d'instructions. Ainsi le style de programmation suivant est tout à fait légal, quoi que peu utilisé.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
public class Demo {

    public static void main( String [] args ) {
    
        {
            int a = (int) (Math.random() * 5);
            int b = (int) (Math.random() * 5);
            int res = a + b;
            System.out.println( "Le calcul aléatoire vaut " + res );
        }
    
        {
            int a = 15;
            System.out.println( "La variable a vaut " + a );        
        }
        
    } 

}
Deux blocs d'instructions à l'intérieur d'un troisième bloc

Le programme ci-dessus met aussi en évidence une caractéristique forte liée d'un bloc d'instructions : un bloc d'instructions permet de contrôler la durée de vie de vos variables. Effectivement, une variable est obligatoirement déclarée dans un bloc d'instructions. A la fin de ce dernier elle est obligatoirement libérée. Du coup, vous ne pourrez plus utiliser ce nom de variable dans votre programme (car libérée).

un petit complément de terminologie, une variable déclarée dans un bloc d'instructions est couramment appelée variable locale. Elle est locale à son bloc. C'est pour insister sur le fait qu'elle n'est visible, à cause de sa durée de vie, que localement dans son bloc de définition.

Une variable est stockée dans un espace de mémoire particulier appelé la pile d'exécution (ou stack, en anglais). L'état de la pile évolue au cours du temps en fonction des variables de l'on définit. Il faut aussi savoir une chose très importante : la taille de la pile d'exécution est limitée. Si vous saturez cette pile d'exécution, une erreur FATALE sera déclenchée. L'erreur produite sera plus précisément de type java.lang.StackOverflowError. En réalité, un programme Java complexe n'a pas qu'une unique pile d'exécution. Effectivement, cette notion de pile est en fait liée à la notion de thread (aussi appelé fil d'exécution) : il existe donc une pile d'exécution par thread. Nous parlerons de threads dans des futurs chapitres.


Evolution de la pile d'exécution au cours du temps

Le diagramme ci-dessus vous montre comment les variables naissent, évoluent et meurent au cours de l'exécution séquentielle de vos instructions. Au final de l'exécution des lignes de code proposées à titre d'exemple, l'état de la pile sera donc revenu dans son état initial, et les variables locales manipulées seront donc définitivement perdues. Notez bien qu'à partir de la ligne 6, la variable b est perdu et ne sera donc plus accessible. Si vous tentez néanmoins de la manipuler, le compilateur Java vous renverra une erreur de compilation.

Voici un code ne compilant pas, car cherchant à utiliser une variable en dehors du bloc dans lequel elle est définie. S'en suivra le message d'erreur produit par le compilateur.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
public class Demo {

    public static void main( String [] args ) {
    
    int a = 4;
    {
        int b = 5;
        a = 6;
        b = 7;
    }

    a = 8;
    b += 1;
    
    System.out.printf( "a==%d et b==%d\n", a, b );
        
    } 

}
Mauvaise gestion des variables
$> javac Demo.java
Demo.java:13: error: cannot find symbol
    b += 1;
    ^
  symbol:   variable b
  location: class Demo
Demo.java:15: error: cannot find symbol
    System.out.printf( "a==%d et b==%d\n", a, b );
                                              ^
  symbol:   variable b
  location: class Demo
2 errors
$> 
si votre variable contient un objet, en fait seule la variable, qui contient un pointeur vers l'objet, sera libérée à ce moment-là. Pour ce qui est de l'objet, il restera en mémoire jusqu'à que le Garbage Collector décide de le détruire et de recycler sa mémoire. L'espace mémoire dans lequel l'objet est instancié est appelé le tas (le heap en anglais). Encore une fois, nous reviendrons sur le fonctionnement du Garbage Collector dans des futurs chapitres.

Les conventions de codage

Depuis la première version publique de Java, leurs inventeurs ont essayé d'imposer un certain nombre de conventions de codage. Force est de constater qu'elles ont étaient fortement suivies. Je vous suggère donc de les suivre vous aussi : cela garantie une meilleure lisibilité de vos programmes. Vous aurez certainement remarqué depuis le début de ce tutoriel que j'essaye, moi aussi et tant que possible, de respecter ces conventions.

Pour ce qui est d'un bloc d'instructions, la convention veut que les instructions qu'il contient soient décalées (on dit indentées) de quatre blancs vers la droite. Cette convention garantie de bien voir la portée (en anglais, le scope) de vos variables. Dès que l'on revient vers la gauche avec une accolade fermante, les variables locales sont perdues.

Par contre, il y a deux grandes écoles de formatage de code quant à la position de l'accolade ouvrante sur une instruction de contrôle (if, for, while, ...). Il y a ceux qui place l'accolade ouvrante à la fin de l'instruction de contrôle (ou de la déclaration de méthode), comme dans le code suivant.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
public class Demo {

    public static void main( String [] args ) {
 
        if ( args == 0 ) {
            System.out.println( "Des paramètres sont requis" );
        }
    
        // Suite du programme
        
    }
    
}
Accolade ouvrante à la fin de l'instruction de contrôle

Et puis, il y a ceux qui placent l'accolade ouvrante à la ligne suivante, comme dans cet exemple de code. Repérez bien les positions des accolades ouvrantes.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
public class Demo {

    public static void main( String [] args )
    {
 
        if ( args == 0 ) 
        {
            System.out.println( "Des paramètres sont requis" );
        }
    
        // Suite du programme
        
    }
    
}
Accolade ouvrante passée à la ligne suivante de l'instruction de contrôle

Comprenez que cela n'a aucun impact sur le résultat de votre programme. Cette considération est uniquement liée à la lisibilité du code. Pour ma part, je préfère la première façon de faire. C'est aussi celle qui est privilégiée par le générateur de code d'Eclipse.

Si vous souhaitez changer cette configuration d'Eclipse, allez dans la barre de menu, cliquez sur « Window » puis sur « Preferences ». Une boîte de dialogue doit s'ouvrir. Dans l'arborescence de gauche allez dans « Java » / « Code Style » / « Formatter ».

Puis éditez votre convention de codage en cliquant sur le bouton « Edit... ». Une nouvelle boîte de dialogue apparait. Veuillez y sélectionner l'onglet « Braces ». La partie de droite vous présente un exemple de code utilisant le formatage que vous aurez choisi.



Synthèse sur les opérateurs Java Les instructions conditionnelles