5. Opérateurs Java
Table des matières
- 5.1 Définition
- 5.2 Types d’opérateurs
- 5.3 Catégories d’opérateurs
- 5.4 Priorité des opérateurs et ordre d’évaluation
- 5.5 Tableau récapitulatif des opérateurs Java
- 5.6 Opérateurs unaires
- 5.7 Opérateurs binaires
- 5.8 Opérateur Ternaire
5.1 Définition
En Java, les opérateurs sont des symboles spéciaux qui effectuent des opérations sur des variables et des valeurs.
Ce sont les briques de base des expressions et ils permettent aux développeurs de manipuler des données, de comparer des valeurs, d’effectuer des opérations arithmétiques et de contrôler le flux logique.
Une expression est une combinaison d’opérateurs et d’opérandes qui produit un résultat.
Par exemple :
int result = (a + b) * c;
Ici, + et * sont des opérateurs, et a, b et c sont des opérandes.
5.2 Types d’opérateurs
Java définit trois types d’opérateurs, regroupés selon le nombre d’opérandes qu’ils utilisent :
| Type | Description | Exemples |
|---|---|---|
| Unary | Opère sur un seul opérande | +x, -x, ++x, --x, !flag, ~num |
| Binary | Opère sur deux opérandes | a + b, a - b, x * y, x / y, x % y |
| Ternary | Opère sur trois opérandes (un seul en Java) | condition ? valueIfTrue : valueIfFalse |
5.3 Catégories d’opérateurs
Les opérateurs peuvent également être regroupés, selon leur objectif, en catégories :
| Catégorie | Description | Exemples |
|---|---|---|
| Assignment | Assigne des valeurs aux variables | =, +=, -=, *=, /=, %= |
| Relational | Compare des valeurs | ==, !=, <, >, <=, >= |
| Logical | Combine ou inverse des expressions booléennes | |, &, ^ |
| Conditional | Combine ou inverse des expressions booléennes | ||, && |
| Bitwise | Manipule des bits | &, |, ^, ~, <<, >>, >>> |
| Instanceof | Teste le type d’un objet | obj instanceof ClassName |
| Lambda | Utilisé dans les expressions lambda | (x, y) -> x + y |
5.4 Priorité des opérateurs et ordre d’évaluation
La priorité des opérateurs détermine comment les opérateurs sont regroupés dans une expression — c’est-à-dire quelles opérations sont effectuées en premier.
L’associativité (ou ordre d’évaluation) détermine si l’expression est évaluée de gauche à droite ou de droite à gauche lorsque des opérateurs ont la même priorité.
Exemple :
int result = 10 + 5 * 2; // La multiplication est effectuée avant l’addition → result = 20
Les parenthèses () peuvent être utilisées pour surclasser la priorité :
int result = (10 + 5) * 2; // Les parenthèses sont évaluées en premier → result = 30
Note
- La priorité des opérateurs concerne le regroupement, pas l’ordre concret d’évaluation.
- Utilise les parenthèses pour la priorité et la clarté dans les expressions complexes.
5.5 Tableau récapitulatif des opérateurs Java
| Priorité (Haute → Basse) | Type | Opérateurs | Exemple | Ordre d’évaluation | Applicable à |
|---|---|---|---|---|---|
| 1 | Postfix Unary | expr++, expr-- |
x++ |
Gauche → Droite | Types numériques |
| 2 | Prefix Unary | ++expr, --expr |
--x |
Gauche → Droite | Numériques |
| 3 | Other Unary | (type), +, -, ~, ! |
-x, !flag |
Droite → Gauche | Numériques, boolean |
| 4 | Cast Unary | (Type) reference |
(short) 22 |
Droite → Gauche | reference, primitifs |
| 5 | Multiplication/division/modulus | *, /, % |
a * b |
Gauche → Droite | Types numériques |
| 6 | Additive | +, - |
a + b |
Gauche → Droite | Numériques, String (concaténation) |
| 7 | Shift | <<, >>, >>> |
a << 2 |
Gauche → Droite | Types intégraux |
| 8 | Relational | <, >, <=, >=, instanceof |
a < b, obj instanceof Person |
Gauche → Droite | Numériques, reference |
| 9 | Equality | ==, != |
a == b |
Gauche → Droite | Tous les types (sauf boolean pour <, >) |
| 10 | Logical AND | & |
a & b |
Gauche → Droite | boolean |
| 11 | Logical exclusive OR | ^ |
a ^ b |
Gauche → Droite | boolean |
| 12 | Logical inclusive OR | | |
a|b |
Gauche → Droite | boolean |
| 13 | Conditional AND | && |
a&&b |
Gauche → Droite | boolean |
| 14 | Conditional OR | || |
a||b |
Gauche → Droite | boolean |
| 15 | Ternary (Conditional) | ? : |
a > b ? x : y |
Droite → Gauche | Tous les types |
| 16 | Assignment | =, +=, -=, *=, /=, %= |
x += 5 |
Droite → Gauche | Tous les types assignables |
| 17 | Arrow operator | -> |
(x, y) -> x + y |
Droite → Gauche | Expressions lambda, switch rules |
5.5.1 Notes complémentaires
- La concaténation de chaînes (
+) a une priorité plus faible que le+arithmétique sur les nombres. - Utilise les parenthèses
()pour la priorité et la lisibilité — elles ne changent pas la sémantique mais rendent l’intention explicite.
5.6 Opérateurs unaires
Les opérateurs unaires opèrent sur un seul opérande pour produire une nouvelle valeur.
Ils sont utilisés pour des opérations comme l’incrémentation/décrémentation, la négation d’une valeur, l’inversion d’un booléen ou le complément bit à bit.
5.6.1 Catégories d’opérateurs unaires
| Opérateur | Nom | Description | Exemple | Résultat |
|---|---|---|---|---|
+ |
Unary plus | Indique une valeur positive (souvent redondant). | +x |
Identique à x |
- |
Unary minus | Indique qu’un nombre littéral est négatif ou nie une expression. | -5 |
-5 |
++ |
Increment | Augmente une variable de 1. Peut être préfixe ou postfixe. | ++x, x++ |
x+1 |
-- |
Decrement | Diminue une variable de 1. Peut être préfixe ou postfixe. | --x, x-- |
x-1 |
! |
Logical complement | Inverse une valeur booléenne. | !true |
false |
~ |
Bitwise complement | Inverse chaque bit d’un entier. Quick rule: ~n = -(n + 1) | ~5 |
-6 |
(type) |
Cast | Convertit la valeur vers un autre type. | (int) 3.9 |
3 |
5.6.2 Exemples
int x = 5;
System.out.println(++x); // 6 (préfixe : incrémente x à 6, puis renvoie 6)
System.out.println(x++); // 6 (postfixe : renvoie 6, puis incrémente x à 7)
System.out.println(x); // 7
boolean flag = false;
System.out.println(!flag); // true
int a = 5; // binaire : 0000 0101
System.out.println(~a); // -6 → binaire : 1111 1010 (complément à deux)
Note
- Préfixe (
++x/--x) : met à jour la valeur d’abord, puis renvoie la nouvelle valeur. - Postfixe (
x++/x--) : renvoie d’abord la valeur courante, puis la met à jour. - L’opérateur
!s’applique aux valeurs boolean ;~s’applique aux types numériques intégraux.
5.7 Opérateurs binaires
Les opérateurs binaires nécessitent deux opérandes.
Ils effectuent des opérations arithmétiques, relationnelles, logiques, bit à bit et d’affectation.
5.7.1 Catégories d’opérateurs binaires
| Catégorie | Opérateurs | Exemple | Description |
|---|---|---|---|
| Arithmetic | +, -, *, /, % |
a + b |
Opérations mathématiques de base. |
| Relational | <, >, <=, >=, ==, != |
a < b |
Compare des valeurs. |
| Logical (boolean) | &, |, ^ |
a&b |
Voir note ci-dessous. |
| Conditional | &&, || |
a&&b |
Voir note ci-dessous. |
| Bitwise (integral) | &, |, ^, <<, >>, >>> |
a << 2 |
Opère sur les bits. |
| Assignment | =, +=, -=, *=, /=, %= |
x += 3 |
Modifie puis affecte. |
| String Concatenation | + |
"Hello " + name |
Concatène des chaînes. |
Important
- Les opérateurs logiques (
&,|,^) évaluent toujours les deux côtés. - Les opérateurs conditionnels (
&&,||) sont short-circuit :a && b→best évalué uniquement siaest truea || b→best évalué uniquement siaest false
Important
Cheat Sheet Pattern Bitwise et Boolean
a ^ a = 0
a ^ 0 = a
a ^ -1 = ~a
a ^ ~a = -1
a & a = a
a | 0 = a
Exemple arithmétique :
int a = 10, b = 4;
System.out.println(a + b); // 14
System.out.println(a - b); // 6
System.out.println(a * b); // 40
System.out.println(a / b); // 2
System.out.println(a % b); // 2
Exemple relationnel :
int a = 5, b = 8;
System.out.println(a < b); // true
System.out.println(a >= b); // false
System.out.println(a == b); // false
System.out.println(a != b); // true
Exemple logique :
boolean x = true, y = false;
System.out.println(x && y); // false
System.out.println(x || y); // true
System.out.println(!x); // false
Exemple bit à bit :
int a = 5; // 0101
int b = 3; // 0011
System.out.println(a & b); // 1 (0001)
System.out.println(a | b); // 7 (0111)
System.out.println(a ^ b); // 6 (0110)
System.out.println(a << 1); // 10 (1010)
System.out.println(a >> 1); // 2 (0010)
5.7.2 Opérateurs de division et de modulo (reste)
5.7.2.1 Opérateur de Division
Diviser un entier par zéro (par exemple, 10 / 0) provoque le lancement par la JVM d’une java.lang.ArithmeticException: / by zero.
Cependant, la division en virgule flottante se comporte différemment.
Lorsqu’une valeur float ou double est divisée par 0 ou 0.0, aucune exception n’est levée. À la place, le résultat est :
- Float.POSITIVE_INFINITY ou Float.NEGATIVE_INFINITY
- Double.POSITIVE_INFINITY ou Double.NEGATIVE_INFINITY
Le signe dépend des opérandes impliqués dans l’opération.
Pour déterminer si une valeur en virgule flottante représente l’infini, les classes Float et Double fournissent des méthodes utilitaires :
Méthodes statiques :
- Float.isInfinite(float value)
- Double.isInfinite(double value)
Méthodes d’instance :
- Float.isInfinite()
- Double.isInfinite()
Ces méthodes retournent true si la valeur correspond à l’infini positif ou à l’infini négatif.
5.7.2.2 Opérateur Modulo
L’opérateur modulo donne le reste lorsque deux nombres sont divisés.
Si deux nombres se divisent exactement, le reste est 0 : par exemple 10 % 5 vaut 0.
En revanche, 13 % 4 donne un reste de 1.
On peut utiliser le modulo avec des nombres négatifs selon les règles suivantes :
- si le diviseur est négatif (ex. : 7 % -5), le signe est ignoré et le résultat est 2 ;
- si le dividende est négatif (ex. : -7 % 5), le signe est conservé et le résultat est -2 ;
System.out.println(8 % 5); // GIVES 3
System.out.println(10 % 5); // GIVES 0
System.out.println(10 % 3); // GIVES 1
System.out.println(-10 % 3); // GIVES -1
System.out.println(10 % -3); // GIVES 1
System.out.println(-10 % -3); // GIVES -1
System.out.println(8 % 9); // GIVES 8
System.out.println(3 % 4); // GIVES 3
System.out.println(2 % 4); // GIVES 2
System.out.println(-8 % 9); // GIVES -8
5.7.3 La valeur de retour de l’opérateur d’affectation
En Java, l’opérateur d’affectation (=) ne fait pas que stocker une valeur dans une variable —
il renvoie aussi la valeur affectée comme résultat de l’expression entière.
Cela signifie que l’affectation peut être utilisée comme partie d’une autre expression,
par exemple dans une condition if, dans la condition d’une boucle, ou même dans une autre affectation.
int x;
int y = (x = 10); // l’affectation (x = 10) renvoie 10
System.out.println(y); // 10
// x = 10 affecte 10 à x.
// L’expression (x = 10) s’évalue à 10.
// Cette valeur est ensuite affectée à y.
// Donc x et y finissent avec la même valeur (10).
Comme l’affectation renvoie une valeur, elle peut aussi apparaître dans un if.
Cependant, cela conduit souvent à des erreurs logiques si c’est fait involontairement.
boolean flag = false;
if (flag = true) {
System.out.println("This will always execute!");
}
// Ici la condition (flag = true) affecte true à flag, puis s’évalue à true,
// donc le bloc if s’exécute toujours.
// Usage correct (comparaison au lieu d’affectation) :
if (flag == true) {
System.out.println("Condition checked, not assigned");
}
Warning
Si tu vois if (x = quelque chose), stop : c’est une affectation, pas une comparaison.
5.7.4 Opérateurs d’affectation composée
Les opérateurs d’affectation composée en Java combinent une opération arithmétique ou bit à bit avec une affectation en une seule étape.
Au lieu d’écrire x = x + 5, tu peux utiliser la forme abrégée x += 5.
Ils effectuent automatiquement un cast implicite vers le type de la variable à gauche lorsque c’est nécessaire.
Les opérateurs composés courants incluent :
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, et >>>=.
int x = 10;
// Affectations composées arithmétiques
x += 5; // équivalent à x = x + 5 → x = 15
x -= 3; // équivalent à x = x - 3 → x = 12
x *= 2; // équivalent à x = x * 2 → x = 24
x /= 4; // équivalent à x = x / 4 → x = 6
x %= 5; // équivalent à x = x % 5 → x = 1
// Affectations composées bit à bit
int y = 6; // 0110 (binaire)
y &= 3; // y = y & 3 → 0110 & 0011 = 0010 → y = 2
y |= 4; // y = y | 4 → 0010 | 0100 = 0110 → y = 6
y ^= 5; // y = y ^ 5 → 0110 ^ 0101 = 0011 → y = 3
// Affectations composées avec décalage
int z = 8; // 0000 1000
z <<= 2; // z = z << 2 → 0010 0000 → z = 32
z >>= 1; // z = z >> 1 → 0001 0000 → z = 16
z >>>= 2; // z = z >>> 2 → 0000 0100 → z = 4
// Exemple de cast de type
byte b = 10;
// b = b + 1; // ❌ erreur de compilation : le résultat int ne peut pas être affecté à byte
b += 1; // ✅ fonctionne : cast implicite vers byte
Note
Les affectations composées effectuent un cast implicite vers le type de la variable à gauche.
C’est pourquoi b += 1 compile alors que b = b + 1 ne compile pas.
5.7.5 Opérateurs d’égalité (== et !=)
Les opérateurs d’égalité en Java == (égal à) et != (différent de) servent à comparer deux opérandes.
Cependant, leur comportement diffère selon qu’ils s’appliquent à des types primitifs ou à des types référence (objets).
Note
==compare les valeurs pour les primitifs==compare les références pour les objets.equals()compare le contenu d’un objet (si implémenté)
5.7.5.1 Égalité avec les types primitifs
Lorsqu’on compare des valeurs primitives, == et != comparent les valeurs stockées.
int a = 5, b = 5;
System.out.println(a == b); // true → mêmes valeurs
System.out.println(a != b); // false → valeurs égales
Important
- Si les opérandes sont de types numériques différents, Java les promeut automatiquement vers un type commun avant la comparaison.
- Cependant, comparer float et double peut produire des résultats inattendus à cause des erreurs de précision (voir ci-dessous).
int x = 10;
double y = 10.0;
System.out.println(x == y); // true → x promu en double (10.0)
double d = 0.1 + 0.2;
System.out.println(d == 0.3); // false → problème d’arrondi floating-point
5.7.5.2 Égalité avec les types référence (objets)
Pour les objets, == et != comparent les références, pas le contenu.
Ils renvoient true uniquement si les deux références pointent vers le même objet en mémoire.
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1 == s2); // false → objets différents en mémoire
System.out.println(s1 != s2); // true → pas la même référence
Même si deux objets ont un contenu identique, == compare leurs adresses, pas leurs valeurs.
Pour comparer le contenu des objets, utilise .equals().
System.out.println(s1.equals(s2)); // true → même contenu de chaîne
Cas particulier : null et littéraux String
- Toute référence peut être comparée à
nullavec==ou!=.
String text = null;
System.out.println(text == null); // true
- Les littéraux String sont internés par la JVM :
des littéraux identiques peuvent donc pointer vers la même référence en mémoire :
String a = "Java";
String b = "Java";
System.out.println(a == b); // true → même littéral interné
- Égalité avec types mixtes :
avec==entre catégories différentes (ex. primitif vs objet),
le compilateur tente l’unboxing si l’un des deux est une classe wrapper.
Integer i = 100;
int j = 100;
System.out.println(i == j); // true → unboxing avant comparaison
5.7.6 L’opérateur instanceof
instanceof est un opérateur relationnel qui teste si une référence est une instance d’un certain type référence à l’exécution.
Il renvoie un boolean.
Object o = "Java";
boolean b1 = (o instanceof String); // true
boolean b2 = (o instanceof Number); // false
Comportement avec null :
si l’expression est null, expr instanceof Type est toujours false.
Object n = null;
System.out.println(n instanceof Object); // false
Warning
instanceof renvoie toujours false lorsque l’opérande gauche est null.
5.7.6.1 Vérification à la compilation vs à l’exécution
- À la compilation, le compilateur rejette les types inconvertibles (qui ne peuvent pas être liés à l’exécution).
- À l’exécution, si la vérification compile-time a passé, la JVM évalue le type réel de l’objet.
// ❌ Erreur de compilation : types inconvertibles (String est sans rapport avec Integer)
boolean bad = ("abc" instanceof Integer);
// ✅ Compile, mais le résultat à l’exécution dépend de l’objet réel :
Number num = Integer.valueOf(10);
System.out.println(num instanceof Integer); // true à l’exécution
System.out.println(num instanceof Double); // false à l’exécution
5.7.6.2 Pattern matching pour instanceof
Java supporte les type patterns avec instanceof, qui testent et lient une variable si le test réussit.
Ajouter une variable après le type indique au compilateur d’interpréter cela comme du Pattern Matching.
Syntaxe (forme pattern) :
Object obj = "Hello";
if (obj instanceof String str) {
// Ajouter la variable str après le type indique au compilateur de faire du Pattern Matching
System.out.println(str.toUpperCase()); // l’identifiant est en scope ici, de type String (sûr).
}
Propriétés clés :
- Si le test réussit, la variable de pattern (ex.
str) est définitivement assignée et visible dans la branche true. - Les variables de pattern sont implicitement final (ne peuvent pas être réassignées).
- Le nom ne doit pas entrer en conflit avec une variable existante dans le même scope.
5.7.6.3 Flow scoping & logique short-circuit
Les variables de pattern deviennent disponibles selon l’analyse de flux :
Object obj = "data";
// Test négatif, variable disponible dans la branche else
if (!(obj instanceof String s)) {
// s n’est pas en scope ici
} else {
System.out.println(s.length()); // s est en scope ici
}
// Avec &&, la variable de pattern peut être utilisée à droite si la gauche l’a établie
if (obj instanceof String s && s.length() > 3) {
System.out.println(s.substring(0, 3)); // s en scope
}
// Avec ||, la variable de pattern n’est PAS sûre à droite (le short-circuit peut empêcher de l’établir)
if (obj instanceof String s || s.length() > 3) { // ❌ s n’est pas en scope ici
// ...
}
// Les parenthèses peuvent aider à regrouper la logique
if ((obj instanceof String s) && s.contains("a")) { // ✅ s en scope après le test groupé
System.out.println(s);
}
Le pattern matching avec null s’évalue, comme toujours pour instanceof, à false :
String str = null;
// instanceof classique
if (str instanceof String) {
System.out.print("NOT EXECUTED"); // instanceof vaut false
}
// Pattern matching
if (str instanceof String s) {
System.out.print("NOT EXECUTED"); // instanceof vaut toujours false
}
Types supportés :
Le type de la variable de pattern doit être un sous-type, un super-type, ou le même type que la variable référence.
Number num = Short.valueOf(10);
if (num instanceof String s) {} // ❌ Erreur de compilation
if (num instanceof Short s) {} // ✅ Ok
if (num instanceof Object s) {} // ✅ Ok
if (num instanceof Number s) {} // ✅ Ok
5.7.6.4 Tableaux et types réifiables
instanceof fonctionne avec les tableaux (réifiables) et avec des formes génériques effacées ou avec wildcard.
Les types réifiables sont ceux dont la représentation à l’exécution conserve pleinement leur type (par exemple : raw types, tableaux, classes non génériques, wildcard ?).
À cause de l’effacement de type (type erasure), List<String> ne peut pas être testée directement à l’exécution.
Object arr = new int[]{1,2,3};
System.out.println(arr instanceof int[]); // true
Object list = java.util.List.of(1,2,3);
// System.out.println(list instanceof List<Integer>); // ❌ Erreur de compilation : type paramétré non réifiable
System.out.println(list instanceof java.util.List<?>); // ✅ true
5.8 Opérateur ternaire
L’opérateur ternaire (? :) est le seul opérateur en Java qui prend trois opérandes.
Il constitue une forme concise de l’instruction if-else.
5.8.1 Règles de Typage de l’Opérateur Ternaire
Le type d’une expression conditionnelle (ternaire) est déterminé par les types du deuxième et du troisième opérande.
5.8.1.1 Opérandes Numériques
- Si un opérande est de type
byteet l’autre de typeshort, le type résultant estshort. - Si un opérande est de type
T(byte,shortouchar) et l’autre est une expression constante de typeintdont la valeur est représentable dansT, alors le type résultant estT. - Dans tous les autres cas numériques, la binary numeric promotion est appliquée aux deux opérandes.
Le type de l’expression conditionnelle devient le type promu.
La binary numeric promotion inclut la conversion d’unboxing et la value set conversion.
5.8.1.2 Types de Référence
- Si un opérande est
nullet l’autre est un type de référence, le type résultant est ce type de référence. - Si les deux opérandes sont de types de référence différents, l’un doit être assignable à l’autre (compatibilité d’assignation).
Le type résultant est le type le plus général, c’est-à-dire celui auquel l’autre peut être assigné. - Si aucun des deux types n’est compatible par assignation avec l’autre, une erreur à la compilation se produit.
En résumé, l’opérateur ternaire détermine son type en appliquant :
- Des règles spécifiques de narrowing pour les petits types entiers
- La binary numeric promotion pour les valeurs numériques
- Les règles de compatibilité d’assignation pour les types de référence
Tip
L’opérateur ternaire doit produire une valeur d’un type compatible. Si les deux branches retournent des types non liés, la compilation échoue.
String s = true ? "ok" : 5; // ❌ erreur de compilation : types incompatibles
5.8.2 Syntaxe
condition ? expressionIfTrue : expressionIfFalse;
5.8.3 Exemple
int age = 20;
String access = (age >= 18) ? "Autorisé" : "Refusé";
System.out.println(access); // "Autorisé"
5.8.4 Exemple de Ternaire Imbriqué
int score = 85;
String grade = (score >= 90) ? "A" :
(score >= 75) ? "B" :
(score >= 60) ? "C" : "F";
System.out.println(grade); // "B"
5.8.5 Remarques
Warning
- Les expressions ternaires imbriquées peuvent réduire la lisibilité. Utilisez des parenthèses pour plus de clarté.
- L’opérateur ternaire retourne une valeur, contrairement à
if-else, qui est une instruction.