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 :
- Toujours s'assurer que les tailles sont compatibles ;
java 0 1 long value = 8.1;//erreur de compilation - 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 :
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 :
(
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 leint
est converti enfloat
puis une comparaison entre deux valeurs flottantes est effectuée//De même, vous pouvez comparer un char à un int
Lechar
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 :
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 : "
+(
objinstanceof
Integer)); System.out.println
(
"obj instanceof Double : "
+(
objinstanceof
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
(
objinstanceof
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 :
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 :
String a =
"Hello"
;
System.out.print
(
a +
5
+
4
); //= Hello54
- 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
- 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
); - Il est possible d'utiliser l'opérateur « += » avec des chaines de caractères :Sélectionnez
String s
=
"123"
; s+=
"45"
; s+=
"67"
;//= 1234567
- 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--
; - 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
- 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
- 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.
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.0
F;
//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 :
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 expressiontrue
: valeur à retourner si expressionfalse
- On peut combiner plusieurs opérateurs conditionnels :
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,
System.out.println
(!
true
);// = false
VIII. Exercices▲
VIII-A. Corrigez les erreurs et trouvez le résultat▲
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▲
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▲
class
Animale {
public
static
void
main
(
String[] args) {
Long x =
12
L;
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▲
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▲
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