next up previous contents index
Next: 5 Les structures de Up: Java: Le langage Previous: 3 Eléments de base

Subsections

4 Opérations et expressions

   

4.1 Généralités sur les expressions

Une expression est un objet syntaxique obtenu en assemblant ``correctement'' des constantes, des variables et des opérateurs. Par exemple, x + 3 est une expression construite en appliquant l'opérateur + sur les opérandes x et 3 . Dans le langage Java, il y a bien d'autres opérateurs que les opérateurs arithmétiques qu'on a l'habitude de manipuler.

  Un programme passe la quasi totalité de son temps à évaluer des expressions pour produire des effets de bord ou pour calculer des valeurs. Une expression avec un effet de bord est une expression qui lorsqu'elle s'évalue, produit un changement de l'état du système. Par exemple, l'affectation est une expression qui a pour effet de bord la modification du contenu de l'opérande gauche. L'invocation d'une méthode est une expression qui lorsqu'elle s'évalue produit comme effet de bord, l'appel de la méthode après évaluation des paramètres de la méthode.

Le résultat de l'évaluation d'une expression est soit une valeur, soit une variable (en C, une lvalue ) soit void. Le résultat de l'évaluation d'une expression est void dans l'unique cas de l'invocation d'une méthode qui ne retourne rien (une procédure).

4.1.1 Priorité des opérateurs

    Nous avons l'habitude de manipuler des expressions (par exemple arithmétiques) et il nous est relativement aisé de préciser exactement le sens des expressions comme : 2 + 3*4*5 - 2 , 2 - 3 - 4 etc. On sait que ces expressions sont équivalentes à (2 + (3*(4*5))) - 2 , (2 - 3) - 4 . Introduire les parenthèses permet de définir sans ambiguïté l'expression que l'on manipule.

A priori, c'est notre culture mathématique qui nous permet de parenthéser ces expressions. Pour éviter l'usage des parenthèses qui alourdissent la lecture, et lorsque cela est possible, les mathématiciens ont fixé des règles pour que tout le monde parenthèse (dans sa tête) de la même manière toute expression ambiguë.

Par exemple, dans l'expression 2 + 3*4 , la sous expression 3*4 est évaluée en premier et le résultat obtenu est ajouté à la valeur 2 (forme parenthésée : 2 + (3*4)) . On dit que l'opérateur * possède une priorité supérieure à la priorité de l'opérateur + . De même, dans l'expression 2 - 3 - 4 , la sous expression 2 - 3 est évaluée en premier et, au résultat obtenu, on soustrait la valeur 4 (forme parenthésée : (2 - 3) - 4) . On dit que l'ordre d'évaluation de l'opérateur - est de gauche à droite.

4.1.2 Ordre d'évaluation

    Comme nous le verrons plus loin, outre les expressions arithmétiques, le langage Java dispose de beaucoup d'autres sortes d'expressions. La donnée d'une priorité et d'un ordre d'évaluation permet de fixer des règles communes d'évaluation des expressions. Ces priorités et ordre d'évaluation ne permettent évidemment pas de se dispenser des parenthèses dans tous les cas. En effet, on utilise les parenthèses lorsqu'on veut évaluer une expression d'une manière autre que celle définie à l'aide de la priorité et de l'ordre d'évaluation. Par exemple, si l'on veut faire 2 + 3 et multiplier le résultat par 4, on sera contraint de noter (2 + 3)*4 et il n'est pas possible de l'écrire sans les parenthèses avec la notation infixée.

Les opérandes de chaque opération sont complètement évalués avant d'effectuer l'opération. Il existe, cependant trois exceptions : il s'agit des opérateurs &&, || et ? :. Java garantit également que les opérandes sont évalués de gauche à droite. Par exemple, dans l'expression x + y , on est sûr que x est évalué avant y . Cette connaissance de l'ordre d'évaluation est particulièrement importantes lorsqu'il s'agit d'expressions avec des effets de bord.

4.1.3 Type d'une expression

  

Toutes les expressions, syntaxiquement correctes, ont un type . Le type des expressions sont toujours connus dès la ``compilation''. Une expression de type T peut être affectée à une variable du même type ou d'un type compatible .

Le type d'expression est donnée par le type des opérandes et de la sémantique des opérateurs. Tous types entiers autre que long sont convertis en int avant d'être évalués. Le résultat est de type int à moins que l'un des opérandes soit de type long.

4.1.4 Erreur d'évaluation d'une expression

   

L'évaluation d'une expression peut conduire à une erreur. Dans ces cas, Java lance une exception (voir 10) précisant la raison exacte de l'erreur.

4.2 Affectation

   

L'opération la plus importante dans un langage de programmation est celle qui consiste à donner une valeur à une variable. Cette opération appelée affectation est désignée par le symbole =.

L'affectation range une valeur dans une variable (une zone mémoire), il est impératif que le membre gauche d'une affectation représente une zone mémoire : c'est ce qu'on appelle une lvalue en C . Une constante n'est pas une lvalue car il ne désigne pas l'adresse d'une zone mémoire. Elle ne peut donc pas figurer en membre gauche d'une affectation.

Le membre droit d'une affectation peut désigner soit une constante soit une zone mémoire soit une expression quelconque : l'affectation x = 2 range la valeur 2 dans la variable x, l'affectation x = y range dans la variable x le contenu de la variable y et l'affectation x = y + 1 range dans la variable x le contenu de la variable y incrémenté de 1.

L'affectation est une expression.
La valeur d'une affectation est la valeur de son membre gauche après exécution de l'affectation. Si la variable y contient la valeur 100 alors l'affectation x=y+20 a pour valeur 120.
Une affectation peut figurer en membre droit d'une autre affectation.
L'affectation x=y=1 est parfaitement valide car elle représente l'affectation x=(y=1). Puisque y=1 est une expression, elle peut figurer en membre droit d'une affectation. Puisque elle est syntaxiquement correcte, quel sens donner à cette affectation ? L'expression y=1 a pour valeur celle de son membre droit (ici la valeur entière 1), l'affectationx=y=1 range dans la variable x la valeur 1 après avoir rangé dans y cette même valeur 1. Ainsi, l'affectation x1=x2=x3=...=x20=0 est équivalent à la suite d'affectations (dans l'ordre indiqué) x20=0, x19=0, x18=0, ..., x1=0.

Une erreur de compilation est générée lorsque le type de l'expression membre droit de l'affectation ne peut être converti en le type du membre gauche.

A l'exécution, si l'opérande gauche n'est pas un élément d'un tableau, l'opérande gauche est tout d'abord évalué, ensuite l'opérande droit est évalué et enfin la résultat de cette dernière est convertie au type de l'opérande gauche. Si durant l'une des ces trois phases, une erreur survient, l'évaluation de l'affectation est immédiatement arrêtée et l'erreur générée pour l'affectation est cette première erreur. Si, par contre, l'opérande gauche est une élément d'un tableau, les opérations effectuées sont les suivants (dans l'ordre) :


 
Table 4.1: Opérateur d'affectation
Précédence Ordre Opérateur Type Description
13 droite gauche = Variable, qcq Affectation

4.3 Expressions arithmétiques

 

Les opérateurs +, - et * fonctionnent comme on s'y attend. Comme en C et C++ , les caractères sont un type particulier d'entier. On peut donc appliquer les opérations arithmétiques sur les caractères. Les expressions 'A' - '0', 'A' + 1 sont syntaxiquement corrects et s'évaluent parfaitement.

Cas des entiers

L'arithmétique entière de Java est une arithmétique complément à deux, modulaire. Cette arithmétique ne produit jamais de débordement car le résultat est toujours réduite modulo le domaine de valeurs du type des opérandes.

Cas des flottants

      Java utilise le standard IEEE 754-1985 pour les nombres à virgules flottantes. Une opération arithmétique peut conduire soit à un underflow (valeur trop petite) ou un overflow (valeur top grande). Une opération sur les flottants peut produire un résultat pour lequel il n'existe pas une approximation permettant de le représenter par un nombre flottant. C'est, par exemple, le cas du résultat d'une division par zéro. Ce type de résultat est représenté par une valeur particulière appelée NaN (Not a Number ).

L'arithmétique flottante Java est un sous ensemble du standard IEEE-754-1985.

4.3.1 Expressions multiplicatifs

 

Tous les opérateurs multiplicatifs ont la même priorité et l'ordre d'évaluation est gauche-droite. Le type des opérandes doit être de type numérique. Le type de l'opération effectué dépend du type (après conversion) de ses opérandes. Le type d'une opération multiplicatif est soit de type entier (int ou long) soit flottant (float ou double).

Les opérations multiplicatifs sont la multiplication (*) , la division (/) et le reste de la division (%). Si l'un des opérande est NaN, le résultat est NaN.


 
Table 4.2: Arithmétique virgule flottante
a b a x b a/b a%b
Fini ± 0.0 rawhtml950.0 rawhtml951#1 NaN
Fini rawhtml951#1 rawhtml951#1 rawhtml950.0 a
rawhtml950.0 rawhtml950.0 rawhtml951#1 NaN NaN
rawhtml951#1 Fini rawhtml951#1 rawhtml951#1 NaN
rawhtml951#1 rawhtml951#1 rawhtml951#1 NaN NaN
rawhtml951#1 rawhtml950.0 NaN NaN NaN


La multiplication

La multiplication, notée avec le symbole *, est une opération commutative sans effet de bord. Elle est associative sur les entiers et ne l'est pas sur les flottants. Lorsque le résultat de la multiplication de deux entiers dépasse des plages de valeurs permises selon le type (int ou long), le résultat est ramené au modulo du type.

La division

Le résultat de la division, notée avec le symbole /, de deux entiers est le quotient de la division entière de ces deux nombres. Le résultat de la division de deux flottants est le quotient de la division de ces deux flottants.

Le reste de la division

Le résultat de la division de deux entiers est le reste de la division entière de ces deux nombres. Contrairement à C et C++ , le reste de la division de deux flottants est également défini pour les nombres à virgules flottantes. Le résultat du reste de la division de a par b est définie par r = a - (b x q) où q est le quotient de a par b .
 
Table 4.3: Opérateurs multiplicatifs
Précédence Ordre Opérateur Type Description
2 gauche droite *, /, % Arithmétique Multiplication, division et reste

4.3.2 Expressions additifs

 

Les opérations additifs, qui sont l'addition (+) et la soustraction (-), ont la même priorité et l'ordre d'évaluation est gauche-droite. Le type des opérandes doit être de type numérique. Le type de l'opération effectué dépend du type (après conversion) de ses opérandes. Le type d'une opération multiplicatif est soit de type entier (int ou long) soit flottant (float ou double).

Les opérations additifs entières, tout comme les opérations multiplicatifs, ne produit aucune erreur. Il n'y pas de débordement possible : l'arithmétique est une arithmétique e complément à 2.

Quant aux opération additifs sur les flottants, la somme de deux infinis produit un NaN si les signes différent et l'infini sinon. La différence de deux infinis de même signe est un NaN. ; sinon le résultat est celui attendu.

 
Table 4.4: Opérateurs additifs
Précédence Ordre Opérateur Type Description
3 gauche droite +, - Arithmétique Addition et soustraction

4.3.3 Opérateurs unaires

Les opérateurs unaires (- ou +) s'appliquent sur un type numérique. Pour les flottants, si x est 0.0 alors - x est égal à - 0.0 alors 0.0 - x = 0.0 .
 
Table 4.5: Opérateurs arithmétiques unaires
Précédence Ordre Opérateur Type Description
1 droite gauche +, - Arithmétique Plus et moins unaire

4.3.4 Pré et post incrément et décrément

       

Il existe deux opérateurs ++ et deux opérateurs - : une pour la forme préfixée et l'autre pour la forme postfixée. Ce sont des opérateurs unaires qui s'appliquent sur un opérande de type numérique.

Opérateur post-incrément et post-décrément (++ et -)

La valeur d'une expression de post-incrément (post décrément) est la valeur de l'opérande et a pour effet de bord, le stockage de la valeur de l'opérande incrémenté (resp. décrémenté) de 1.

Opérateur pré-incrément et pré-décrément(++ et -)

La valeur d'une expression de pré-incrément (pré-décrément) est la valeur de l'opérande incrémenté (resp. décrémenté) de 1 et a pour effet de bord, le stockage de cette valeur.

 
Table 4.6: Opérateurs d'incrément et de décrément
Précédence Ordre Opérateur Type Description
1 droite gauche ++, - Arithmétique Incrémént et décrément

4.4 Expressions de comparaison

 

Le résultat d'une compraison est une valeur boolénne (vrai ou faux). Dans le langage Java, le résultat d'une comparaison est true ou false selon que cette comparaison est vraie ou fausse.

 
Table 4.7: Opérateurs de comparaison
Précédence Ordre Opérateur Type Description
5 gauche droite <,<=, >, >= Arithmétique Comparaison arithmétique
6 gauche droite ==, != objet et type primitif egalité et différent

4.5 Concaténation des chaînes de caractères

    Si l'un des opérandes de l'opérateur + est un objet de type String, alors la sémantique de cette opération est la concaténation de chaînes. Si besoin, l'autre opérande est converti en String.
 
x = 2 ; y = 3 ;
System.out.println("Le produit de " +  x  +  " et de " +  y +  " est : " +  x*y) ;
produit la sortie
 
Le produit de 2 et de 3 est : 6

 
Table 4.8: Opérateur de concaténation de chaînes
Précédence Ordre Opérateur Type Description
3 gauche droite + Chaînes de caractères Concaténation de chaînes

4.6 Expressions logiques

 

On dispose des connecteurs logiques (sous une syntaxe particulière) et on peut fabriquer des expressions avec celles-ci. La valeur d'une expression booléenne est, comme le résultat des comparaisons, une valeur booléenne.

Comme d'habitude, l'évaluation d'une expression booléenne obéit aux règles de priorité et à l'ordre d'évaluation. Java propose deux types d'opérateurs logiques : les opérateurs classiques et les opérateurs conditionnels.

L'évaluation des opérations classiques se fait par l'évaluation complète de chaque opérande et l'application de l'opération sur les résultats obtenus.

L'évaluation des opérateurs conditionnels se fait par évaluation successives des opérandes. Cette évaluation s'arrête dès que l'on est capable de donner la valeur de l'expression. Par exemple, en supposant que la variable x contient la valeur 5, l'évaluation de l'expression (x >= 2) || ( x >= y) s'arrête avant même d'avoir évalué l'expression x >= y, puisque (x >= 2) est vrai d'où on peut conclure que la valeur de l'expression (x >= 2) || ( x >= y) est également vraie.

Cette remarque a son importance dans deux cas :


 
Table 4.9: Opérateur booléens
Précédence Ordre Opérateur Type Description
1 droite gauche ! Booléen non booléen
7 gauche droite & Booléen ET booléen
8 gauche droite ^ Booléen OU exclusif booléen
9 gauche droite | Booléen OU booléen
11 gauche droite && Booléen ET conditionnel booléen
11 gauche droite || Booléen OU conditionnel booléen

4.7 Manipulation de bits

 

4.7.1 Opérations bits à bits

On dispose des opérateurs suivants :


 
Table 4.10: Opérateurs bit à bit
Précédence Ordre Opérateur Type Description
1 droite gauche ~ Entier complément bit à bit
7 gauche droite & Entier ET bit à bit
8 gauche droite ^ Entier OU exclusif bit à bit
9 gauche droite | Entier Ou bit à bit

4.7.2 Décalage de bits

L'opérateur << décale les bits vers la gauche en complétant par des bits à zéro sur la partie droite. L'opérateur >>> décale les bits vers la droite en complétant par des bits à zéro sur la partie gauche. L'opérateur >> décale les bits vers la droite en complétant par des bits à la valeur du bit de poids fort sur la partie gauche.

Précédence Ordre Opérateur Type Description

 
Table 4.11: Opérateurs de décalage de bits
Précédence Ordre Opérateur Type Description
4 gauche droite <<, >>, >>> Entier Décalage de bits

4.8 Autres opérateurs binaires d'affectation

 

Les opérateurs suivants ne sont que des raccourcis de notation : les expressions y += x, y -= x, y *= x, y /= x, y %= x, y >>= x, y <<= x, y >>>= x, y &= x, y ^= x et y |= x, correspondent aux raccourcis pour y = y+x, y = y-x, y = y*x, y = y/x, y = y%x, y = y>>x, y = y<<x, y = y>>>x, y = y&x, y = y^x et y = y|x.


 
Table 4.12: Autres opérateurs d'affectation
Précédence Ordre Opérateur Type Description
    =,    
13 droite gauche *=, /=, %=, +=, -=, Variable, qcq Affectation simple et
    <<=, >>=, >>>=,   avec opérations
    &=, ^=, |=    

4.9 Expression conditionnelle

 

Voici l'opérateur ternaire (le seul). Cette expression est une sorte de si-alors-sinon sous forme d'expression : si la condition e est vraie alors cette expression vaut x sinon elle vaut y.

Exemple :

L'expression a = (v ==2) ? 1 : 2 affecte la variable a à la valeur 1 si v vaut 2, sinon affecte la variable a à la valeur 2.
 
Table 4.13: opérateur conditionnel
Précédence Ordre Opérateur Type Description
12 droite gauche ? : Booléen, qcq Si-alors-sinon

4.10 Changement de type

   

Cet opérateur permet de convertir explicitement le type d'une donnée en un autre type. L'opérateur de parenthèsage () permet de définir l'ordre d'évaluation d'une expression. C'est l'opérateur que l'on utilise traditionnellement. C'est également ce même opérateur qui est utilisé pour encapsuler les paramètres des fonctions. Même lorsqu'une fonction n'a pas d'arguments, ces parenthèses sont requises.

Le problème de la conversion des types se pose lorsqu'une expression est composée de données de nature différentes. Par exemple, quel sens donner à une addition d'un entier et d'un nombre flottant ? Que se passe-t-il lorsqu'on affecte un variable de type entier à une valeur de type caractère ou flottant. La langage Java définit précisément quelles sont les types de données compatibles et quel type de conversion est effectué.

La conversion explicite d'un opérande se fait en le préfixant du type choisi encadré par des parenthèses.

 
double d = 2.5 ;
long l = (long) d ;

4.10.1 Les conversions implicites

Les conversions implicites sont celles faites automatiquement par un compilateur lors de l'évaluation d'une expression (et donc également d'une affectation). Comme nous le verrons plus loin, il y a conversion implicite lors de l'invocation d'une méthode. Il y a deux type de conversion implicite :

1.
Les valeurs entières peuvent être affectées à toute variable numérique dont le type support un domaine de valeur plus grand. Un char est peut utilisé partout où une valeur de type int est permis. Les valeurs de type flottant peuvent être affectées à toute variable de type flottant de précision supérieure ou égale. Les données de type entières peuvent être converties en données de type flottant.
 
long i = 0x7effffffffffffffL ;          // 91513144428168478771 
float f = i ;                           // 9.15131e+18 
long l = (long)f ;                      // 91513144428168478772
2.
Le second type de conversion implicite concerne les référence vers des objets : partout une référence vers un objet d'un type T est requise, une référence vers un objet d'une sous classe de T peut être fournie. La référence null peut être fournie pour tout type de référence y compris les tableaux.

4.10.2 Les conversions explicites

 

On utilise la conversion explicite pour changer le type d'une donnée. Ce changement ne peut être arbitraire : seules certaines conversions sont permises. Par exemple, on ne peut convertir un boolean en int mais un double peut être converti en un long.

Pour savoir si un objet o d'une certaine classe est convertible en un objet d'une autre classe C, on utilisera un test de la forme :
 
if (o instanceof C)

 
Table 4.14: Opérateur de changement de type
Précédence Ordre Opérateur Type Description
1 droite gauche (type ) qcq Changement de type
5 gauche droite instanceof objet Comporaison de type

Nous verrons plus loin, en détails, les changements de type permis et ceux interdits.

4.11 Création des objets

4.11.1 Cas des objets

Comme nous le verrons plus loin, les objets complexes et structurés à l'aide des classes. Ces classes sont ``une sorte de struct C ''. Les classes possèdes des champs et des méthodes . L'opérateur d'accès à ces membres des classes est le ``.''.

4.11.2 Cas des tableaux

Nous verrons également que les tableaux sont d'un type particulier d'objets. Les éléments des tableaux tab sont notés tab[i]. L'opérateur [] sert d'accès d'opérateur d'accès aux éléments d'un tableau.

 
Table 4.15: Opérateur d'accès aux membres
Précédence Ordre Opérateur Type Description
1 droite gauche ., [] objet Accès aux membres

4.12 Récapitulatif


 
Table 4.16: Récapitulatif
Précédence Ordre Opérateur Type Description
1 droite gauche ++, - Arithmétique Incrémént et décrément
1 droite gauche +, - Arithmétique Plus et moins unaire
1 droite gauche   Entier complément bit à bit
1 droite gauche ! Booléen non booléen
1 droite gauche (type) qcq Changement de type
1 droite gauche ., [] objet Accès aux membres
1 droite gauche (type) qcq Changement de type
2 gauche droite *, /, % Arithmétique Multiplication, division et reste
3 gauche droite +, - Arithmétique Addition et soustraction
3 gauche droite + Chaînes de caractères Concaténation de chaînes
4 gauche droite <<, >>, >>> Entier Décalage de bits
5 gauche droite <,<=, >, >= Arithmétique Comparaison arithmétique
5 gauche droite instanceof objet Comparaison de type
6 gauche droite ==, != objet et type primitif égalité et différent
7 gauche droite   Entier et booléen ET bit à bit et booléen
8 gauche droite ^ Entier et booléen OU exclusif bit à bit et booléen
9 gauche droite | Entier et booléen Ou bit à bit et booléen
11 gauche droite && Booléen ET conditionnel
11 gauche droite || Booléen OU conditionnel
12 droite gauche ? : Booléen, qcq, qcq Si-alors-sinon
    =,    
13 droite gauche *=, /=, %=, +=, -=, Variable, qcq Affectation simple et
    <<=, >>=, >>>=,   avec opérations
    &=, ^=, |=    


next up previous contents index
Next: 5 Les structures de Up: Java: Le langage Previous: 3 Eléments de base
Touraivane
6/12/1998