I. Introduction

Plusieurs parmi nous (je suis le premier) ont appris le langage Java en rassemblant des bouts de code dans le but de réaliser un logiciel (ce que l'on a coutume d'appeler formation sur le tas). Quoique cela a toujours fini par donner un résultat, on ne saurait cependant renier son inconvénient majeur : à la fin on ne sait jamais comment les choses fonctionnent au fond. Ce qui peut avoir pour conséquences : la mauvaise utilisation des types d'objets et de la mémoire qui parfois occasionne des pertes en temps énormes suite à une mauvaise approche lors du débogage.

À la suite du troisième chapitre qui traitait des types de variables, des affectations, du transtypage, de la portée des variables, de la gestion des tableaux et du garbage collector, ce chapitre (qui est le troisième de la suite le mémo du certifier Java SE 6) va s'attarder sur les différents opérateurs offerts par Java SE 6 en prenant le soin d'élucider leur mode opératoire. Comme opérateurs, nous parlerons des opérateurs relationnels, de l'opérateur instanceof, des opérateurs arithmétiques, de l'opérateur conditionnel et enfin des opérateurs logiques. À l'issue de cette présentation, cinq exercices corrigés sont mis à la disposition du lecteur pour des besoins d'évaluation personnelle. Je conseille vivement que ce test soit effectué avant et après la lecture de l'article.

Les opérateurs sont des symboles qui permettent de manipuler des variables. On en distingue plusieurs types en Java. Pour facilement les étudier, nous allons les classer en catégories.

II. Quelques règles de base

  • En ce qui concerne les primitives, il faut :
  1. Toujours s'assurer que les tailles sont compatibles ;
     java 01 
    long value = 8.1;//erreur de compilation
  2. Connaître exactement quand la conversion (cast) implicite ou explicite des variables s'applique et dans quel cas il y a troncature. Dans l'exemple suivant, la méthode calculVitesse () retournera zéro tandis que la méthode demarreVoiture() lèvera une exception de type NullPointerException :
 
Sélectionnez
public class Voiture {

  private Boolean started;

  public static void main(String[] args) {
    System.out.println(new Voiture().calculVitesse(19.8, 20));
    new Voiture().demarreVoiture();
  }

  public void demarreVoiture() {
   boolean isStarted = started;//NPE
   if (isStarted) {
            //...
   }
  }

  public long calculVitesse(double distance, long temps) {
    long d = (long) distance; 
    return d/temps;
  }
}
  • En ce qui concerne les variables de référence, il faut :
  • Parmi les opérateurs d'affectation composés, les plus utilisés sont les suivants : (+=, -=, /=, *=) :
     
    Sélectionnez
    (y = y -6;) = (y -= 6;) and (x = x + 2*5;) = (x += 2*5)
    
  • Dans le cas des opérateurs d'affectation composés, l'expression qui se trouve du côté droit du signe d'égalité est toujours évaluée en premier :
 
Sélectionnez
(x *= 2 + 5;) = (x = x * (2+5))

III. Les opérateurs relationnels

Encore appelés opérateurs de comparaison, ils retournent un résultat de type boolean et permettent d'évaluer le rapport entre les valeurs de deux opérandes.

  • L'examen pour la certification Java SE 6 prend en compte six opérateurs relationnels : (<, <=, >, >=, ==, and!=).
  • Les opérateurs relationnels ne s'appliquent que sur les primitives de type numérique et retournent toujours des valeurs booléennes comme résultat.
  • Si les opérandes ne sont pas des primitives de même type, alors, le plus petit opérande est promu au type du plus grand opérande avant que la comparaison ne soit effectuée :
     
    Sélectionnez
    //Vous pouvez comparer un int et un float; 
    Premièrement le int est converti en float puis une comparaison entre deux valeurs flottantes est effectuée 
    //De même, vous pouvez comparer un char à un int
    Le char est d'abord transformé en int avant que la comparaison ne soit faite
    
  • Le résultat d'une opération relationnelle est toujours un booléen (true ou false). Ce résultat est le plus souvent utilisé pour des tests conditionnels avec if. Cependant, il peut aussi être directement affecté à une primitive booléenne :
     
    Sélectionnez
    int x = 1;
    if(x>9){}
    boolean b = x > 9; //c'est correct
    
  • En Java, on retrouve quatre opérateurs relationnels qui peuvent être utilisés pour comparer n'importe quelle combinaison d'entiers, de nombres décimaux ou de caractères : (>, >=, <, <=).
  • Il est possible de faire une comparaison entre une primitive de type caractère et un nombre quelconque,
     
    Sélectionnez
    char c = 'c';        
    if(c > 10.2) {
      //fait quelque chose
    }
    
  • Lorsqu'on compare un caractère avec un caractère ou un caractère avec un nombre, Java utilise la valeur Unicode du caractère comme valeur de comparaison.
  • Java possède aussi deux opérateurs relationnels pour comparer l'égalité entre deux variables (==,!=). Il est impossible de comparer deux variables de types incompatibles.
  • L'opérateur « == » compare les valeurs contenues dans les variables. Ainsi, deux références d'objet seront égales si elles pointent sur le même objet en mémoire. Alors que, deux primitives seront égales si elles contiennent la même valeur :
     
    Sélectionnez
    Object obj1 = new Object();
    Object obj2 = new Object();
    Object obj3 = obj1;
                    
    System.out.println("obj1 == obj2 : "+(obj1 == obj2)+" obj1 == obj3 : "+(obj1 == obj3));
    //résultat  obj1 == obj2 : false obj1 == obj3 : true
            
    int i = 10;
    double d = 10.0;
            
    System.out.println("i == d : "+(i == d));
    //résultat  i == d : true
    
  • Pour le type enum, l'opérateur « == » permet de déterminer si deux variables désignent la même constante :
 
Sélectionnez
enum Color {RED,GREEN}
Color a = Color.RED;
Color b = Color.RED;
System.out.println("a=b : "+(a == b));
//résultat :  a=b : true

Tableau  : Tableau des opérateurs relationnels

Opérateur Description Exemple
== égal x == y
!= différent de x!= y
< Strictement plus petit que x < y
<= plus petit que ou égal à x <= y
> Strictement plus grand que x > y
>= plus grand que ou égal à x >= y

IV. L'opérateur instanceof

  • L'opérateur instanceofs'applique uniquement aux références d'objet. Il permet de vérifier qu'une variable est d'un type précis :
     
    Sélectionnez
    Integer i = 1;
    Object obj = i;
                    
    System.out.println("obj instanceof Integer : "+(obj instanceof Integer));
    System.out.println("obj instanceof Double : "+(obj instanceof Double));
    //result :
    /*
      obj instanceof Integer : true
      obj instanceof Double : false
    */
    
  • L'opérateur instanceofpermet deprotéger le programme des erreurs de conversion entre types :
     
    Sélectionnez
    public boolean equals(Object obj){
        if(obj instanceof String){
            String value = (String) obj; //ok
            return this.equals(value);
        }else {// la variable obj ne peut pas être convertie en String
            return false;
        }     
    }
    
  • Il est possible de tester si la référence null est l'instance d'une classe. Bien évidemment le résultat sera toujours false :
     
    Sélectionnez
    System.out.println("null instanceof String : "+(null instanceof String)); 
    //null instanceof String : false
    
  • On ne peut pas utiliser l'opérateur instanceofpour faire des tests entre deux classes appartenant à des hiérarchies distinctes. L'instruction suivante produira une erreur de compilation :
 
Sélectionnez
String s;
if(s instanceof Integer) //erreur de compilation

V. Les opérateurs arithmétiques

Ils permettent d'effectuer des calculs mathématiques avec des variables.

  • L'opérateur de congruence (%), il permet de calculer le reste de la division de la variable de gauche par la variable de droite :
     
    Sélectionnez
    int y = 15 % 4;// Le résultat est  : 3
    
  • Le signe (+) peut aussi être utilisé pour concaténer deux chaines de caractères :
     
    Sélectionnez
    String s = "Mouton "+"blanc";
    System.out.println(s);//Mouton blanc
    
  • Règles concernant l'opérateur +.Si l'un des opérandes est une chaine de caractères, l'opérateur + devient un opérateur de concaténation de chaines de caractères :
 
Sélectionnez
String a = "Hello"; 
System.out.print(a +5 + 4); //= Hello54
  1. Si les deux opérandes sont des nombres, l'opérateur + est un opérateur d'addition :
     
    Sélectionnez
    String a = "Hello";
    System.out.print(5+4+""+a);// = 9Hello
    
  2. Si l'un des opérandes est une expression entre parenthèses, cette expression sera d'abord évaluée :
     
    Sélectionnez
    String a = "Hello";
    System.out.print(a + (5+4));// = Hello9
    
     
    Sélectionnez
    /* si foo() retourne un nombre "+" fait l'addition. 
     Mais si foo() est une chaine de caractères alors "+" concatène */
    
    System.out.print(foo() + 7);
    
  3. Il est possible d'utiliser l'opérateur « += » avec des chaines de caractères :
     
    Sélectionnez
    String s = "123"; s += "45"; s +="67";//= 1234567
    
  4. Le langage Java contient deux opérateurs qui permettent d'incrémenter et de décrémenter les variables de 1. Ces opérateurs sont : ++ et --. Ils sont placés soit avant soit après la variable dont on veut changer la valeur :
     
    Sélectionnez
    int i = 0; ++i; i++; --i; i--;
    
  5. Lorsqu'on place l'opérateur d'incrémentation avant la variable (++i), elle est incrémentée avant usage, mais quand l'opérateur est placé après (i++), la variable est incrémentée après son utilisation (un petit puzzle à propos) :
     
    Sélectionnez
    int i = 0; 
    System.out.println(i++);//=0
    System.out.println(i+" ");//=1
    System.out.println(++i+" ");//=2
    System.out.println(i);//=2
    
  6. Parfois, les opérateurs composés nous permettent d'éviter la conversion entre différents types :
     
    Sélectionnez
    long l = 100;
    int i = 5;
    i = l*i;// erreur de compilation
    i *= l;//ok
    
  7. Lorsqu'on utilise les opérateurs suivants : (+, -,*,/,%), si les opérandes sont de types distincts, les plus petits opérandes sont promus au plus grand. Ceci dit, si vous additionnez un short et un int la variable short sera promue au type int et l'addition se fera entre deux int. Si les opérandes sont de type inférieur au type int, ils seront promus au type int avant l'opération.
 
Sélectionnez
short s1 = 10, s2 = 12;
short sum = s1 + s2;    //erreur de compilation!
//Le type short(16 bits) est inférieur au type int(32 bits), alors les deux opérandes (s1 et s2) seront promus au type int avant l'opération. D'où le résultat de l'opération sera une valeur de type int. Pour corriger cette erreur, il faut faire un cast.

short sum = (short) (s1 + s2); //ok
int a = 26, b = 5;
double d = a / b;
//d = 5.0   
//L'expression a/b est une division entière d'où le résultat sera 5
int a = 26;
float f = a / 5.0F;
//f = 5.2
//Puisque 5.0 est de type float, la variable a de type int sera promue au type float. Ainsi on aura affaire à une division décimale

VI. Opérateur conditionnel

L'opérateur conditionnel est un opérateur ternaire (composé de trois éléments) qui permet d'évaluer des expressions booléennes à l'aide d'une structure conditionnelle compacte :

 
Sélectionnez
Type var 
var = Condition ? Expression_1 : Expression_2;//opérateur conditionnel
// est équivalent à 
if (Condition) {//test avec le if
  var = Expression_1;
} else {
  var = Expression_2;
}
  • On construit cet opérateur en faisant usage des symboles « » et « ». Les parenthèses sont optionnelles et sa structure est la suivante :
     
    Sélectionnez
    x = (boolean expression) ? valeur à retourner si expression true : valeur à retourner si expression false
    
  • On peut combiner plusieurs opérateurs conditionnels :
 
Sélectionnez
String status = (num < 4) ? "count OK" : (size > 8) ? "limit" : "too many";

VII. Les opérateurs logiques

Les opérateurs logiques permettent de comparer des expressions booléennes et retournent des valeurs booléennes.

  • Pour ce qui concerne l'examen de certification, il est demandé de prendre en compte six opérateurs logiques : (&,|, ^,!, && et ||).
  • Pour les opérateurs &, ^, et |, les deux opérandes doivent être : soient de type numérique soient des expressions booléennes. Si les deux opérandes sont numériques, ces opérateurs sont des opérateurs de bits. Et si les opérandes sont de type booléen, ces opérateurs sont des opérateurs logiques.
  • Les opérateurs && et || opèrent uniquement sur des valeurs booléennes.
  • Pour qu'une expression avec le && soit true, il faut que les deux opérandes soient true.
     
    Sélectionnez
    if((2 < 4) && (3<4)){}
    
  • L'opérateur && évalue d'abord l'opérande de gauche, s'il est false, toute l'expression sera false et le second opérande ne sera pas évalué.
     
    Sélectionnez
    int i = 0;
    if((++i > 3) && (++i > 1))
        System.out.println("1- i = "+i);
    System.out.println("2- i = "+i); 
    i = 0;
    if((++i < 3) && (++i > 1))
        System.out.println("3- i = "+i);
    System.out.println("4- i = "+i);
    /*resultat :
        2- i = 1
        3- i = 2
        4- i = 2
    */    
    
  • L'opérateur || est similaire à l'opérateur && à la seule différence qu'une expression avec le || sera true si l'un des opérandes est true. Ici, le second opérande est évalué si la première est false.
     
    Sélectionnez
    int i = 0;
    if((++i > 3) || (++i > 1))
        System.out.println("1- i = "+i);
    System.out.println("2- i = "+i); 
    i = 0;
    if((++i < 3) || (++i > 1))
        System.out.println("3- i = "+i);
    System.out.println("4- i = "+i);
    /* resultat :
        1- i = 2
        2- i = 2
        3- i = 1
        4- i = 1
    */
    
  • Les opérateurs | et & sont utilisés dans des expressions logiques au même titre que les opérateurs || et &&. À la seule différence qu'ils évaluent toujours les deux opérandes.
  • L'opérateur ^ (le ou exclusif) évalue seulement les valeurs booléennes. Pour qu'une expression avec l'opérateur ^ soit true, il faut qu'un seul des opérandes soit true.
     
    Sélectionnez
    System.out.println((true ^ true));//false
    System.out.println((true ^ false));//true
    System.out.println((false ^ false));//false
    
  • L'opérateur! (inverse) retourne l'inverse d'une valeur booléenne,
 
Sélectionnez
System.out.println(!true);// = false

VIII. Exercices

VIII-A. Corrigez les erreurs et trouvez le résultat

 
Sélectionnez
class Taille {
  public static void main(String []args) {
    Double t = 160.0;
    String sexe = "M";
    String s = (t<150)? (sexe == "M" ? "Petit" : "Grande"):
         (sexe == "F" ? "Petite" : "Grand");
    System.out.println(s);
  }
}

VIII-B. Corrigez les erreurs et trouvez le résultat

 
Sélectionnez
class Test {
  public static void main(String[] args) {
    int i;
    String[] var = new String[]{"test"};
    
    if(var.length == 1 | var[1].equals("test") | ++i > 0) {
      System.out.println("valeur i : "+i);
    } 
    
    if(var.length == 1 || var[1].equals("test") || ++i > 0) {
     System.out.println("valeur i : "+i);
    }
  }
}

VIII-C. Corrigez les erreurs et trouvez le résultat

 
Sélectionnez
class Animale {
  public static void main(String[] args) {
    Long x = 12L;
    Long y = 14;
    System.out.print(" " + 1 + 2 + " ");
    System.out.print(" " + (1 + 2) + " ");
    System.out.print(manger() + x + 3 + " ");
    System.out.println(x + y + manger());   
  }
  public String manger() { return "mange"; }
}

VIII-D. Corrigez les erreurs et trouvez le résultat

 
Sélectionnez
public class Tierce {
    { index = 1; }
    int index;
    public static void main(String[] args) {
      new Tierce().depart();
    }
    void depart() {
      int [][] dd = {{9,8,7}, {6,5,4}, {3,2,1,0}};
      System.out.println("1-"+dd[index++][++index]);
      System.out.println("2-"+dd[++index][index++]);
    }
    
    { index++; }
}

VIII-E. Corrigez les erreurs et trouvez le résultat

 
Sélectionnez
class EtreVivant { }
  interface Chasseur { }
  class Animale implements EtreVivant { }
  class Chien extends Animale implements Chasseur { }
  public class Tree {
    public static void main(String[] args) {
      String s = "0";
      Animale b = new Animale();
      Animale b2 = new Chien();
      Chien s2 = new Chien();
      if((b instanceof EtreVivant) && (b2 instanceof Chasseur))  s += "1";
      if((s2 instanceof EtreVivant) && (s2 instanceof Chasseur)) s += "2";
      System.out.println(s);
    }
  }

IX. Correction des exercices

IX-A. Exercice 1

  • Erreurs
    Il n'y a aucune erreur. On peut combiner plusieurs opérateurs conditionnels et il est bien possible d'effectuer une comparaison entre un double et un int. Dans ce cas, l'opérande int est promu au type double avant que la comparaison ne soit effectuée.
  • Solution
    La solution est : Grand.

IX-B. Exercice 2

  • Erreurs
    Il faut initialiser la variable i. Une variable locale doit être initialisée avant toute utilisation. Sinon, on aboutira à une erreur de compilation.
    En Java, l'index des tableaux commence à 0 et l'opérateur | évalue toujours tous les opérandes. Ceci étant, l'opérande var[1].equals("test") de la condition if(var.length == 1 | var[1].equals("test") | ++i > 0) sera évalué, ce qui entrainera l'exception ArrayIndexOutOfBoundsException. Il faudra donc remplacer l'index 1 par 0 dans cette condition. Dans la condition if(var.length == 1 || var[1].equals("test") || ++i > 0) cette modification ne sera pas nécessaire parce que le premier opérande var.length == 1 est déjà vrai et l'opérateur n'évaluera donc pas la seconde condition.
  • Solution
    C'est uniquement dans le premier if que la variable i sera incrémentée. D'où le résultat :
    valeur i : 1
    valeur i : 1

IX-C. Exercice 3

  • Erreurs
    Ajoutez un L ou un l à la suite du nombre 14 pour rendre le type compatible.
    Ajouter le modificateur d'accès static à la méthode manger() pour qu'elle puisse être appelée dans la méthode statique main().
  • Solution
    Le résultat est : 12 3 mange123 26mange.

IX-D. Exercice 4

  • Erreurs
    Lors de l'exécution, le premier println() sera équivalent à l'expression suivante : System.out.println("1-"+dd[2][4]); Ce qui ne correspond à aucune position dans notre tableau, d'où l'exception : ArrayIndexOutOfBoundsException.
  • Solution
    Le résultat sera fonction des modifications apportées.

IX-E. Exercice 5

  • Erreurs
    On n'implémente pas une classe, mais on l'étend. Ceci dit, il faudra remplacer class Animale implements EtreVivant par class Animale extends EtreVivant.
  • Solution
    Le résultat de l'opération sera : 012

X. Conclusion

Le prochain article parlera principalement du contrôle du flux, des exceptions et des assertions. L'on verra entre autres : les structures conditionnelles, les boucles, la gestion des exceptions, et les assertions. Mais avant de nous quitter, je voudrais adresser mes remerciements à ClaudeLELOUP pour la relecture orthographique, à thierryler pour ses propositions et keulkeul pour ses propositions, ses encouragements et le temps consacré aux diverses relectures.

Pour réaliser cet article, j'ai fait usage de deux livres que je trouve complémentaires et que je n'hésite pas à vous conseiller. Il s'agit de :

SCJP Sun Certified Programmer for Java 6 Study Guide de Kathy Sierra et Bert Bates ;

A Programmer's Guide to Java™ SCJP Certification Third Edition de Khalid A. Mughal et Rolf W. Rasmussen.

Suivez moi sur twitter