Accès rapide :
Les opérateurs de transtypage (cast operators)
Les opérateurs arithmétiques
Les opérateurs de manipulation de la représentation binaire de vos nombres
Les opérateurs logiques
Les opérateurs de comparaisons
Les opérateurs d'affectations
Les opérateurs travaillant sur les chaînes de caractères
Les autres opérateurs Java
La table de précédence des opérateurs Java
Vos programmes Java vont, logiquement, calculer un certain nombre d'expressions. Une expression est constituée d'opérateurs et d'opérandes. Ainsi
l'expression 3 + 4
est basée sur l'opérateur + et met en jeu les opérandes 3 et 4. Le résultat de cette expression (très simple) valant
bien entendu 7. Comme nous allons le voir, le langage Java propose un très grand nombre d'opérateurs : ils sont, en très grosse partie, récupérés du
langage de programmation C. Nous allons tout au long de ce chapitre présenter l'utilisation des principaux opérateurs de langage à grand renfort d'exemples
de code Java.
Les opérateurs de transtypage (pour la suite, je préférerai la terminologie anglo-saxonne d'opérateurs de cast). Permettent de transformer une donnée d'un
type en une donnée d'un autre type. On peut utiliser des opérateurs de cast explicites ou implicites, selon qu'il y ait ou non, une perte d'information
durant la transformation. Par exemple si vous cherchez à transformer un double
en un float
, on passe d'un type plus précis à un
type moins précis : l'utilisation d'un cast explicite est donc obligatoire pour confirmer l'éventuelle perte de précision. Dans l'autre sens, le cast est
implicite (vous pouvez néanmoins explicitement l'écrire).
Syntaxiquement parlant, on reconnaît un opérateur de cast par le fait qu'il est obligatoirement entre parenthèses et que son nom est obligatoirement un nom de type. L'exemple ci-dessous vous montre quelques exemples de cast : les casts implicites sont repérés par la présence du cast sous forme d'un commentaire (il est néanmoins présent de par son aspect implicite).
01 public class TestCasts { 02 03 public static void main( String [] args ) { 04 05 // cinq cast implicites : on passe d'un type plus 06 // petit vers un type plus grand 07 byte byteValue = 111; 08 short shortValue = /* (short) */ byteValue; 09 int intValue = /* (int) */ shortValue; 10 long longValue = /* (long) */ intValue; 11 float floatValue = /* (float) */ intValue; 12 double doubleValue = /* (double) */ longValue; 13 14 // Cinq cast explicites : si vous ne les mettez 15 // pas, des erreurs vous seront retournées. 16 doubleValue = 12345678901.123456789; 17 floatValue = (float) doubleValue; // vous acceptez la perte de précision 18 longValue = (long) doubleValue; // Idem 19 intValue = (int) longValue; // Idem 20 shortValue = (short) intValue; // Idem 21 byteValue = (byte) shortValue; // Idem 22 23 System.out.println( doubleValue ); 24 System.out.println( floatValue ); 25 System.out.println( longValue ); 26 System.out.println( intValue ); 27 System.out.println( shortValue ); 28 System.out.println( byteValue ); 29 30 } 31 32 }
Les opérateurs arithmétiques permettent, bien entendu, de constituer des expressions arithmétiques. Ces opérateurs sont quasiment utilisables sur tous les types
numériques (byte
, short
, int
, long
, float
et double
). Ces opérateurs sont
au nombre de cinq : +
(pour l'addition), -
(pour la soustraction), *
(pour la multiplication), /
(pour la division) et %
(pour le reste de la division entière). L'exemple qui suit vous montre quelques exemples d'utilisations des opérateurs
arithmétiques.
01 public class TestOperators { 02 03 public static void main( String [] args ) { 04 05 int first = 9; 06 int second = 4; 07 int result; 08 09 result = first + second; // Calcule 13 10 System.out.println( "9+4 == " + result ); 11 12 result = first - second; // Calcule 5 13 System.out.println( "9-4 == " + result ); 14 15 result = first * second; // Calcule 36 16 System.out.println( "9*4 == " + result ); 17 18 result = first / second; // Calcule 2 19 System.out.println( "9/4 == " + result ); 20 21 result = first % second; // Calcule 1 22 System.out.println( "9%4 == " + result ); 23 24 } 25 26 }
Méfiez-vous néanmoins des opérateurs /
et %
: leur comportement dépend que l'on travaille sur des types entiers ou des types
flottants. Effectivement, une source d'erreur classique est la suivante : l'opérateur /
, s'il est invoqué avec deux entiers renverra,
obligatoirement, une valeur entière. L'exemple ci-dessous vous met face à la problématique.
01 public class TestOperators { 02 03 public static void main( String [] args ) { 04 05 // Calcule la valeur 0, car nous avons demandé la division entière !!! 06 // La valeur est transformée en double APRES le calcul. 07 double firstResult = 1 / 3; 08 System.out.println( "1/3 == " + firstResult ); 09 10 // Calcule la valeur 0.3333333432674408 (division flottante simple précision) 11 double secondResult = 1 / (float)3; // ou secondResult = 1 / 3.0f; 12 System.out.println( "1/(float)3 == " + secondResult ); 13 14 15 // Calcule la valeur 0.3333333333333333 (division flottante double précision) 16 double thirdResult = 1 / (double)3; // ou secondResult = 1 / 3.0; 17 System.out.println( "1/(double)3 == " + thirdResult ); 18 19 } 20 21 }
Si vous mixez deux types distincts lors de l'utilisation d'un opérateur arithmétique, c'est toujours le type le plus large qui l'emporte :
3 + 3.6
calcule une valeur de type double
et non entière. Enfin, notez qu'il existe un ordre de priorité entre les différents
opérateurs : la dernière partie de ce chapitre vous présentera la table de précédence des opérateurs Java. L'utilisation des parenthèses vous permettra
d'influer sur l'ordre d'évaluation de vos opérateurs. L'exemple qui suit vous montre ces points par l'exemple.
01 public class TestOperators { 02 03 public static void main( String [] args ) { 04 05 double doubleResult = 3L + 3.5; 06 System.out.println( "3L+3.5 == " + doubleResult ); 07 08 09 float floatResult = (float)(3 + 3.5); 10 System.out.println( "(float)(3+3.5) == " + floatResult ); 11 12 13 int intResult1 = 3 + 2 * 4; // calcule 11 14 int intResult2 = (3 + 2) * 4; // calcule 20 15 System.out.println( intResult1 + " / " + intResult2 ); 16 17 } 18 19 }
Ils permettent de manipuler la représentation binaire de vos nombres entiers.
Les opérateurs binaires sont : &
, |
, ^
, ~
, <<
, >>
et >><
.
Notez aussi les variantes combinées à des affectations : &=
, |=
, ^=
, <<=
, >>=
et >><=
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public class Demo { public static void main( String [] args ) { int value1 = 0b10101010; int value2 = 0b00001111; // & (AND) | (OR) ^ (XOR) ~ (NOT) System.out.println( "NOT - " + Integer.toBinaryString( ~value1 ) ); System.out.println( "AND - " + Integer.toBinaryString( value1 & value2 ) ); System.out.println( "OR - " + Integer.toBinaryString( value1 | value2 ) ); System.out.println( "XOR - " + Integer.toBinaryString( value1 ^ value2 ) ); int value = 0b00010001; // << (signed left shift) >> (signed right shift) >>> (unsinged right shift) System.out.println( "2 x << - " + Integer.toBinaryString( value ) + " -> " + Integer.toBinaryString( value << 2 ) + " [" + value + " -> " + (value << 2) + "]"); System.out.println( "2 x >> - " + Integer.toBinaryString( value ) + " -> " + Integer.toBinaryString( value >> 2 ) + " [" + value + " -> " + (value >> 2) + "]"); System.out.println( "2 x >>> - " + Integer.toBinaryString( -1 ) + " -> " + Integer.toBinaryString( -1 >>> 2 ) + " [-1 -> " + (-1 >>> 2) + "]"); } } |
Les opérateurs logiques acceptent obligatoirement des opérandes booléens et calculent un résultat booléen. Ils sont très fortement utilisés dans
instructions de tests (if
ou switch
) et dans les instructions de boucles (notamment pour terminer une boucle). Ils sont au nombre
de trois : && (le et logique), || (pour le ou logique) et le ! (pour le non logique).
01 public class TestOperators { 02 03 public static void main( String [] args ) { 04 05 boolean debugMode = false; 06 07 if ( args.length>0 && args[0].equals("debug") ) { 08 debugMode = true; 09 System.out.println( "Le mode debug est activé" ); 10 } 11 12 if ( ! debugMode ) { 13 System.out.println( "Action a ne pas faire en mode debug" ); 14 } 15 } 16 17 }
Les opérateurs de comparaisons permettent, comme vous vous en doutez, de réaliser des comparaisons entre des données. Il y a six opérateurs de comparaison
: ==
(pour le test d'égalité), !=
(pour le test de non-égalité), <=
(pour le test d'infériorité),
<
(pour le test d'infériorité stricte), >=
(pour le test de supériorité) et enfin >
(pour le
test de supériorité stricte). Voici un petit exemple d'utilisation de ces opérateurs.
01 public class TestOperators { 02 03 04 public static void main( String [] args ) { 05 06 if ( args.length == 0 ) { 07 System.out.println( "Usage: java TestOperators age" ); 08 System.exit( 0 ); 09 } 10 11 int age = Integer.parseInt( args[0] ); 12 13 if ( age < 18 ) { 14 System.out.println( "Vous êtes mineur" ); 15 System.exit( 0 ); 16 } 17 18 if ( age >= 18 && age <= 65 ) { 19 System.out.println( "Vous êtes certainement actif" ); 20 System.exit( 0 ); 21 } 22 23 if ( age < 100 ) { 24 System.out.println( "Vous êtes certainement à la retraite" ); 25 System.exit( 0 ); 26 } 27 28 System.out.println( "Alors là, respect !" ); 29 30 } 31 32 }
Tous les langages dérivés du langage C (C++, Java bien entendu, JavaScript, C#, ...) présentent une caractéristique remarquable : contrairement aux autres
langages (Pascal, ...), l'affectation n'est pas une instruction mais bien un opérateur. Il en découle que l'affectation calcule une valeur, à savoir la
valeur affectée. L'exemple suivant vous montre deux manières d'exploiter cette possibilité. En ligne 07, plusieurs affectations sont cascadées : l'ordre
d'associativité de l'opérateur est de la droite vers la gauche (on affecte 0 à e - le résultat est 0 que l'on affecte à d - et ainsi de suite ...). En
ligne 14, on affecte une valeur à une position d'un tableau : le résultat de cette affectation est encore une fois la valeur affectée. Du coup, on se sert
de cette valeur pour calculer la condition de sortie de la boucle while
.
01 public class TestOperators { 02 03 public static void main( String [] args ) { 04 05 // On peut cascader les affectations 06 int a, b, c, d, e; 07 a = b = c = d = e = 1; 08 int somme = a + b + c + d + e; // Calcule 5 09 System.out.println( "Somme == " + somme ); 10 11 // On peut se servir d'une affectation comme valeur de test 12 int [] tableau = new int[ 5 ]; 13 int position = 0; 14 while ( ( tableau[ position ] = position ) != 4 ) { 15 position ++; 16 } 17 18 for( position=0; position<5; position++ ) { 19 System.out.println( tableau[ position ] ); 20 } 21 22 } 23 24 }
Notez que l'opérateur = n'est pas le seul opérateur permettant de modifier le contenu d'une variable : à l'instar du langage C, de nombreux opérateurs permettent de coupler une opération avec une affectation. Le tableau ci-dessous liste l'ensemble de ces opérateurs. Notez aussi la présence des opérateurs ++ et -- qui permettent de réaliser, respectivement, une incrémentation et une décrémentation.
Opérateur | Explications complémentaires |
---|---|
+= | Ex: a += 2; équivaut quasiment à a = a + 2; |
-= | Ex: a -= 2; équivaut quasiment à a = a - 2; |
*= | Ex: a *= 2; équivaut quasiment à a = a * 2; |
/= | Ex: a /= 2; équivaut quasiment à a = a / 2; |
%= | Ex: a %= 2; équivaut quasiment à a = a % 2; |
&= | Ex: a &= 2; équivaut quasiment à a = a & 2; |
|= | Ex: a |= 2; équivaut quasiment à a = a | 2; |
^= | Ex: a ^= 2; équivaut quasiment à a = a ^ 2; |
<<= | Ex: a <<= 2; équivaut quasiment à a = a << 2; |
>>= | Ex: a >>= 2; équivaut quasiment à a = a >> 2; |
>>= | Ex: a >>>= 2; équivaut quasiment à a = a >>> 2; |
++ | Ex: a++; équivaut quasiment à a = a + 1; |
-- | Ex: a--; équivaut quasiment à a = a - 1; |
01 public class TestOperators { 02 03 public static void main( String [] args ) { 04 05 // Utilisation des opérateurs += et ++ 06 int [] tableau = new int[ 5 ]; 07 08 for( int i=0; i<5; i+=1 ) { 09 tableau[ i ] = i * i; 10 } 11 12 for( int i=0; i<5; i++ ) { 13 System.out.println( tableau[ i ] ); 14 } 15 16 // Attention aux opérateurs ++ et -- 17 int a = 5; 18 System.out.println( "++ en préfixé - first display " + a++ ); 19 System.out.println( "++ en préfixé - second display " + a ); 20 21 a = 5; 22 System.out.println( "++ en postfixé - first display " + (++a) ); 23 System.out.println( "++ en postfixé - second display " + a ); 24 25 } 26 27 }
Deux opérateurs déjà présentés dans ce document peuvent aussi être utilisé avec des chaînes de caractères ; il s'agit des opérateurs + et +=. Dans ce cas ils n'effectueront pas d'additions, mais bien des concaténations de chaînes de caractères. Ces possibilités ont déjà largement été utilisées dans les exemples précédents.
Le tableau suivant présente quelques autres opérateurs du langage Java. Hormis le dernier, ils sont tous repris du langage C++ : leurs fonctionnements restent similaires. A la suite de ce tableau vous trouverez un petit exemple d'utilisation de certains de ces opérateurs.
Opérateur | Explications complémentaires |
---|---|
new |
Cet opérateur permet d'allouer dans le tas (le heap, en anglais) un bloc de mémoire : il retourne une référence (un pointeur) sur le bloc
de mémoire alloué. Nous avons déjà testé cet opérateur lors de l'allocation d'un tableau (int [] tb = new int[10]; ). Si vous
êtes développeur C++, notez que son homologue delete n'existe pas en Java (le Garbage Collector de la JVM étant chargé de libérer
les ressources).
|
[] | Cet opérateur permet notamment d'accéder aux éléments d'un tableau. |
. | Opérateur de travers : il est utilisé pour accéder aux champs (attributs et méthodes) des objets. Par exemple :
"string".toUpperCase() .
|
? : |
Opérateur conditionnel (c'est le seul opérateur acceptant trois opérandes en Java). Il permet de renvoyer une expression ou un autre en
fonction du résultat d'une troisième expression. Sa syntaxe est la suivante : expTest ? expThen : expElse .
|
instanceof | Permet de tester si un objet est compatible avec un type de données particulier. Cet opérateur tient compte du polymorphisme (nous y reviendrons ultérieurement). |
01 public class TestOperators { 02 03 public static int min( int a, int b ) { 04 return a <= b ? a : b; 05 } 06 07 public static void main( String [] args ) { 08 09 // Test de l'opérateur conditionnel 10 System.out.println( "min(3, 4) == " + min( 3, 4 ) ); 11 12 // Test de l'opérateur instanceof 13 Object ptr = args; // Par polymorphisme (on verra plus tard) 14 System.out.println( ptr instanceof String ); 15 16 ptr = "toto"; 17 System.out.println( ptr instanceof String ); 18 19 } 20 21 }
Comme vous l'avez certainement déjà remarqué, il est possible de se servir de parenthèses pour fixer l'ordre d'évaluation des sous-expressions formant une expression Java. Ainsi, les expressions 3*2+4 et 3*(2+4) n'auront pas les mêmes valeurs (10 et 18). Mais attention tout de même : l'utilisation abusive des parenthèses rend très rapidement un code illisible. Dans le but de ne pas arriver dans de telles situations, sachez que des règles de priorités ont étaient définies sur les opérateurs. Le tableau suivant fixe cet ordre : des plus prioritaires (en haut) aux moins prioritaires (en bas).
Priorité | Operateurs | Description | Associativité |
---|---|---|---|
Les plus prioritaires | () |
Opérateur parenthèse Accès à une entrée d'un tableau Sélection d'un membre |
De la gauche vers la droite |
expr++ |
Incrémentation postfixe Décrémentation postfixe |
De la droite vers la gauche | |
++expr |
Incrémentation préfixe Décrementation préfixe Opérateur unaire de signe positif Opérateur unaire de signe négatif Négation logique Complément binaire (not) Opérateur de transtypage (cast) |
De la droite vers la gauche | |
* |
Multiplication Division Modulo (reste de la division entière) |
De la gauche vers la droite | |
+ |
Addition Soustraction |
De la gauche vers la droite | |
<< |
Décalage de bits vers la gauche Décalage de bits vers la droite Décalage de bits vers la droite (non signé) |
De la gauche vers la droite | |
< |
Infériorité stricte Infériorité Supériorité stricte Supériorité Vérification du typage |
De la gauche vers la droite | |
== |
Egalité Différence |
De la gauche vers la droite | |
& | « ET » en représentation binaire | De la gauche vers la droite | |
^ | « OU exclusif » (XOR) en représentation binaire | De la gauche vers la droite | |
| | « OU » en représentation binaire | De la gauche vers la droite | |
&& | « ET » logique | De la gauche vers la droite | |
|| | « OU » logique | De la gauche vers la droite | |
?: | L'opérateur conditionnel | De la droite vers la gauche | |
Les moins prioritaires | = += -= *= /= %= <<= >>= >>>= &= ^= |= | Affectations combinées | De la droite vers la gauche |
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 :