Vous êtes sur la page 1sur 172

class HelloW

orld {

Introduction
public static
void
System.out.p main(String[] args)
rintln("Hello {
} world");

1
class HelloW
orld {
public static
void
System.out.p main(String[] args)
rintln("Hello {
} world");

001001010100010010010
101010100101001010010
101010101010010010010
101001000101001011000

CAFEBABE00000032001D0A0006000F09 . . . . . . . 2 . . . . . . . .
000010 001000110800120A0013001407001507 . . . . . . . . . . . . . . . .
000020 00160100063C696E69743E0100032829 . . . . . < i n i t > . . . ( )
000030 56010004436F646501000F4C696E654E V . . . C o d e . . . L i n e N

compilateur
000040 756D6265725461626C650100046D6169 u m b e r t a b l e . . . m a i
000050 6E010016285B4C6A6176612F6C616E67 n . . . ( [ L j a v a / l a n g
000060 2F537472696E673B295601000A536F75 / S t r i n g ; ) V . . . S o u
000070 72636546696C6501000F48656C6C6F57 r c e F i l e . . . H e l l o w
000080 6F726C642E6A6176610C000700080700 o r l d . j a v a . . . . . .
000090 170C0018001901000B48656C6C6F2077 . . . . . . . . . H e l l o w
0000A0 6F726C6407001A0C001B001C01000A48 o r l d . . . . . . . . . . . H
0000B0 656C6C6F576F726C640100106A617661 e l l o w o r l d . . . j a v a
0000C0 2F6C616E672F4F626A6563740100106A / l a n g / O b j e c t . . . j
0000D0 6176612F6C616E672F53797374656D01 a v a / l a n g / S y s t e m .
0000E0 00036F75740100154C6A6176612F696F . . o u t . . . L j a v a / i o
0000F0 2F5072696E7453747265616D3B010013 / P r i n t S t r e a m ; . . .
000100 6A6176612F696F2F5072696E74537472 j a v a / i o / P r i n t S t r
000110 65616D0100077072696E746C6E010015 e a m . . . p r i n t l n . . .
000120 284C6A6176612F6C616E672F53747269 ( L j a v a / l a n g / S t r i
000130 6E673B29560021000500060000000000 n g , ) V . ! . . . . . . . . .

class HelloW
orld {
bytecode class HelloW
orld {
public static public static
void void

machine
System.out.p main(String[] args) System.out.p main(String[] args)
rintln("Hello { rintln("Hello {
} world"); } world");

virtuelle
001001010100010010010
101010100101001010010
101010101010010010010
101001000101001011000

2
réfléchir au problème; réfléchir au problème;
concevoir la séquence d'instructions concevoir la séquence d'instructions

? class HelloW
orld {
public static
void
System.out.p main(String[] args)
rintln("Hello {
} world");

écrire un programme Java à


Erreurs à la compilation:
partir de cette réflexion
le programme source ne respecte
pas les règles du langage Java

compiler le programme Java


pour créer un programme en
bytecode

réfléchir au problème; réfléchir au problème;


concevoir la séquence d'instructions concevoir la séquence d'instructions

Erreurs à l'exécution:
class HelloW
orld {
public static
le programme a été mal conçu class HelloW
orld {
public static
void void
System.out.p main(String[] args) System.out.p main(String[] args)
rintln("Hello { rintln("Hello {
} world");
tester le programme sur la } world");
tester le programme sur la
machine virtuelle machine virtuelle

écrire un programme Java à écrire un programme Java à


partir de cette réflexion partir de cette réflexion

compiler le programme Java compiler le programme Java


pour créer un programme en pour créer un programme en
bytecode bytecode

3
Une variable possède 3 caractéristiques:
•  Son identificateur, qui est le nom par lequel la donnée

Les variables est désignée;


•  Son type, qui définit de quel « genre » est la donnée
contenue dans la variable;
•  Sa valeur. Par exemple, si la donnée est un nombre, sa
valeur pourra être 123 ou 3.14 n

123

class ExempleVariable Déclarations de variables


{
public static void main(String[] args) Les lignes:
{
int n = 4;
type de la variable identificateur, ou nom, de la variable.
int nCarre; Il est choisi par le programmeur et permet de
nCarre = n * n; référer la variable créée

System.out.println("La variable n contient " + n);


int n = 4;
System.out.println("Le carre de " + n + " est " + nCarre + "."); int nCarre;
System.out.println("Le double de n est " + 2 * n + ".");
}
} sont des déclarations de variables.

Une déclaration de variable permet de créer une variable.

1
Initialisation Initialisation
Une variable non initialisée ne peut être utilisée.
En même temps qu'elle est déclarée, une variable peut être initialisée, c'est-à-
dire lui donner une valeur avant de l'utiliser.
Par exemple:
La ligne: n nCarre
int nCarre;
System.out.println(nCarre);
int n = 4; 4 ?
donne une erreur à la compilation:
déclare donc une variable appelée n et lui donne la valeur 4.
variable nCarre might not have been initialized
System.out.println(nCarre);

type pour les valeurs entières: la variable n


n nCarre ne peut contenir que des valeurs entières

4 ? int n = 4;
int n = 4; double x = 1.0; n x
int nCarre;
type pour les valeurs décimales:
la variable x ne peut contenir que 4 1.0
des valeurs décimales

2
Déclaration de variables Déclaration de variables
De façon générale, une déclaration de variable suit le schéma: D'autres exemples de déclaration:

int m = 1;
type identificateur = valeur_initiale; on peut déclarer plusieurs variables
int p = 1, q = 0;
simultanément.
double x = 0.1, y; Ne pas en abuser
ou éventuellement:
N'oubliez pas le point-virgule ; à la fin

type identificateur;

Une fois défini, le type de la variable ne peut plus changer.

Noms de variables Conventions en Java


Règles pour nommer les variables: pour les noms de variables
–  Le nom peut être constitué uniquement de lettres, de chiffres, et des deux seuls
symboles autorisés: _ (underscore) et $. Pas d’espace ! En Java, bien que ce ne soit pas requis par le compilateur, la convention est d'écrire le
–  Le premier caractère est nécessairement une lettre ou un symbole; nom des variables en commençant par une minuscule, et commencer les mots suivants
par une majuscule.
–  Le nom ne doit pas être un mot-clé réservé par le langage Java;
–  Les majuscules et les minuscules sont autorisées mais ne sont pas équivalentes. Par exemple, on utilisera
Les noms ligne et Ligne désignent deux variables différentes.
nombreDePoints
Exemples de noms valides:
nCarre Total sousTotal98
plutôt que
Exemples de noms invalides: NombreDePoints
ou
n carre Contient des espaces; 1element Commence par un chiffre.
nombre_de_points
n-carre Contient le symbole – (moins);

3
Types de variables Affectations
La ligne:
Les principaux types élémentaires sont:

–  int, pour les valeurs entières (pour integer, entiers en anglais); nCarre = n * n;
–  double, pour les nombres à virgule, par exemple 0.5
est une affectation.
et aussi:
Attention, ce n'est pas une égalité mathématique: Une affectation est
–  float: aussi pour les nombres à virgule, moins précises mais occupant une instruction qui permet de changer une valeur à une variable.
moins de mémoire que les doubles;
–  char: pour les caractères (A..Z etc.);
–  …

Affectations Affectations
L'exécution d’une affectation se décompose en deux temps : L'exécution d’une affectation se décompose en deux temps :

1 L'expression à droite du signe = est évaluée:


n * n est évaluée avec la valeur de n au moment de l’exécution.
L’étoile * représente la multiplication, n * n vaut donc 4 × 4 = 16

16 nCarre n
16 nCarre n

nCarre = n * n; ? 4 2 nCarre = n * n; ?
16 4
la valeur de l’expression est stockée dans la variable
à gauche du signe =
L’ancienne valeur de nCarre est perdue.

4
Affectations
De façon plus générale, une affectation suit le schéma: Attention: Ne confondez pas une affectation avec une égalité mathématique.

nom_de_variable = expression;
Toutes les deux utilisent le signe égal =, mais l'affectation est un mécanisme
dynamique.
N'oubliez pas le point-virgule ; à la fin
Une expression calcule une valeur, qui doit être de même type que la
Par exemple, les deux instructions:
variable.
Exemples d'expression: copie la valeur de b dans a
a = b;
•  4
b = a; copie la valeur de a dans b
•  n * n
•  n * (n + 1) + 3 * n – 2
ne sont pas identiques.
Nous reviendrons sur les expressions un peu plus loin.

En mathématiques:
On peut écrire aussi des affectations telles que:
b=a+1
a = a + 1;
signifie que tout au long des calculs, a et b vérifieront toujours cette relation.
Autrement dit, quel que soit a, b sera toujours égal à a+1
Ce type d’affectation, où une variable apparaît de chaque côté du signe =
permet de résoudre de nombreux problèmes.

En Java:
Cette affectation signifie:
a = 5;
« calculer l’expression de a + 1 et ranger le résultat dans a. Cela revient à
b = a + 1; donne à b la valeur de a+1, c’est-à-dire 6. augmenter de 1 la valeur de a »
a = 2; Nous reviendrons sur ce point dans la suite.
donne à a la valeur 2, sans que b ne soit modifiée!
b contient donc toujours 6.

5
Déclaration de constantes
Il peut arriver que la valeur d'une variable ne doive pas changer après
l'initialisation. Dans ce cas, il faut ajouter le mot-clé final devant la déclaration:

final type identificateur = valeur_initiale;

Par exemple:

final double VITESSE_DE_LA_LUMIERE = 299792.458;

Dans ce cas, on ne peut plus modifier la variable:

VITESSE_DE_LA_LUMIERE = 100; // erreur !

6
Expression et Opérateurs
A droite du signe égal dans une affectation se trouve une expression:

Expressions nom_de_variable = expression;

Une expression calcule une valeur, qui doit être de même type que la
variable.

Une expression peut être simplement une valeur littérale:


4
3.14

ou une formule qui met en oeuvre des opérateurs:


n * n
n * (n + 1) + 3 * n - 2

Les valeurs littérales et leurs types


•  1 est de type int;
Opérateurs
•  1.0 est de type double;
On dispose des 4 opérateurs usuels:
•  1. est équivalent à 1.0, et donc de type double. On peut écrire:
double x = 1.;
au lieu de Il vaut mieux écrire 1.0 plutôt que 1. puisque + pour l’addition;
double x = 1.0; c'est plus lisible Attention: si la division se fait entre
•  On peut utiliser la notation scientifique, par exemple écrire 2e3 pour 2×103, c’est-à- - pour la soustraction; int, il s'agit de la division entière.
dire 2000. Par exemple:
De façon générale: aeb vaut a×10b. Par exemple:
* pour la multiplication; 1 / 2 vaut 0
double x = 1.3e3; 5 / 2 vaut 2
à x vaut 1.3×103 = 1.3 × 1000 = 1300
/ pour la division. mais
double y = 1.3e-3; 1 / 2.0 vaut bien 0.5
à y vaut 1.3×10-3 = 1.3 × 0.001 = 0.0013

1
On dispose aussi des opérateurs += , -= , *= , /= Opérateurs relatifs au type int
Par exemple: Dans le cas des int, il existe aussi:

a += 5; •  un opérateur modulo, noté %, qui renvoie le reste de la division entière:


est équivalent à 11 % 4 vaut 3
a = a + 5; (la division de 11 par 4 a pour reste 3 car 11 = 2 * 4 + 3).

0 % 4 vaut 0 car 0 = 0 * 4 + 0
1 % 4 vaut 1 car 1 = 0 * 4 + 1
b *= a; 2 % 4 vaut 2 car 2 = 0 * 4 + 2
est équivalent à 3 % 4 vaut 3 car 3 = 0 * 4 + 3
b = b * a; 4 % 4 vaut 0 car 4 = 1 * 4 + 0
5 % 4 vaut 1 car 5 = 1 * 4 + 1
...

Opérateurs relatifs au type int Affectation d’une valeur décimale à


Dans le cas des int, il existe aussi: une variable entière
En Java, il est impossible d'affecter une valeur décimale par exemple de
•  deux opérateurs notés ++ et --, qui permettent respectivement type double à une variable de type int:
d’incrémenter et de décrémenter, c’est-à-dire d’ajouter et de soustraire 1 à
une variable. Exemple:
double x = 1.5;
Par exemple, l’instruction: int n = 3 * x; // Erreur !!!
++i;
est équivalente à : Le compilateur produit le message d'erreur suivant :
i = i + 1; error: possible loss of precision
n = 3 * x;
Ces deux opérateurs sont souvent utilisés avec l’instruction for, que nous ^
verrons par la suite. required: int
found: double

2
Affectation d’une valeur entière à La division entière
une variable décimale
En revanche, il est possible d'affecter une valeur de type int à une variable
de type décimale, par exemple double.

Exemple: double x;
l'expression 1 / 2 est d'abord évaluée
int n = 3;
x = 1 / 2; elle vaut 0
double x = 2 * n;
0 la valeur 0 est affectée à x

0.0

La division entière La division entière


Le problème peut se poser par exemple quand on calcule la moyenne de deux
valeurs entières: Une solution possible:

int note1 = 4; int note1 = 4;


int note2 = 5; int note2 = 5;

double moyenne = (note1 + note2) / 2; double moyenne = (note1 + note2);


moyenne /= 2;
Dans ce cas, moyenne vaut 4 au lieu de 4.5

3
Fonctions mathématiques
Java fournit les fonction mathématiques usuelles, ainsi que des constantes comme Pi.
Fonctions mathématiques
Ces fonctions et constantes s'utilisent en suivant la notation:

Math.nomFonction(expression1, expression2, ...);


L'ensemble des fonctions disponibles est documenté dans:
Math.nomConstante
http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html
Par exemple:

class ExempleMathematique
{
public static void main(String[] args) {

double angle = 10 * Math.PI / 180;


double s = Math.sin(angle);
}
}

import java.util.Scanner;

class ExempleAngle
{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

System.out.println("Entrez un angle en degres: ");


double angleEnDegres = scanner.nextDouble();
double angleEnRadians = Math.PI * angleEnDegres / 180;
System.out.println("Sa valeur en radians est " + angleEnRadians);
System.out.println("Son cosinus vaut " + Math.cos(angleEnRadians));
}
π angle en degrés
} angle en radians =
180

4
Pour écrire à l’écran
affiche la valeur de la variable n
fonction d'affichage
Les variables : sur le terminal
(et non pas la lettre n)

lecture / écriture ce qui est entre guillemets


(") est affiché littéralement

System.out.println("La variable n contient " + n + ".");

affiche: les différents éléments à


afficher doivent être
La variable n contient 4.
séparés par le symbole +

Pour écrire à l’écran


On peut afficher uniquement la valeur d'une variable en faisant simplement:
affiche la valeur de la variable n
fonction d'affichage (et non pas la lettre n) System.out.println(n);
sur le terminal
n

ce qui est entre guillemets On peut aussi afficher la valeur d'une expression: 4
(") est affiché littéralement
System.out.println("Le double de " + n + " est " + 2 * n + ".");

System.out.println("La variable n contient " + n + "."); expression


affiche: System.out.println fait un "retour à la ligne": le prochain Attention, si on veut afficher une somme:
la fonction
affichage se fera sur la ligne suivante de la fenêtre Terminal. System.out.println("n plus nCarre = " + (n + nCarre));
La variable n contient 4.
Il existe une variante qui ne fait pas de retour à la ligne: System.out.print il faut ajouter des parenthèses pour éviter une ambiguité.

1
Déroulement du programme pas-à-pas n

int n = 4;
int nCarre;
int n = 4;
int nCarre;
4
nCarre = n * n; nCarre = n * n;

System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);
System.out.println("Le carre de " + n + " est " + nCarre + "."); System.out.println("Le carre de " + n + " est " + nCarre + ".");
System.out.println("Le double de n est " + 2 * n + "."); System.out.println("Le double de n est " + 2 * n + ".");

Ce qui s'affiche : Ce qui s'affiche :


▌ ▌

n nCarre n nCarre

int n = 4;
int nCarre;
4 ? int n = 4;
int nCarre;
4 ?
nCarre = n * n; nCarre = n * n;

System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);
System.out.println("Le carre de " + n + " est " + nCarre + "."); System.out.println("Le carre de " + n + " est " + nCarre + ".");
System.out.println("Le double de n est " + 2 * n + "."); System.out.println("Le double de n est " + 2 * n + ".");

Ce qui s'affiche : Ce qui s'affiche :


▌ ▌

2
n nCarre n nCarre

int n = 4;
int nCarre;
4 16 int n = 4;
int nCarre;
4 16
nCarre = n * n; nCarre = n * n;

System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);
System.out.println("Le carre de " + n + " est " + nCarre + "."); System.out.println("Le carre de " + n + " est " + nCarre + ".");
System.out.println("Le double de n est " + 2 * n + "."); System.out.println("Le double de n est " + 2 * n + ".");

Ce qui s'affiche : Ce qui s'affiche :


▌ ▌

n nCarre n nCarre

int n = 4;
int nCarre;
4 16 int n = 4;
int nCarre;
4 16
nCarre = n * n; nCarre = n * n;

System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);
System.out.println("Le carre de " + n + " est " + nCarre + "."); System.out.println("Le carre de " + n + " est " + nCarre + ".");
System.out.println("Le double de n est " + 2 * n + "."); System.out.println("Le double de n est " + 2 * n + ".");

Ce qui s'affiche : Ce qui s'affiche :


La variable n contient 4. La variable n contient 4.
▌ Le carre de 4 est 16.

3
n nCarre Qu’affiche ce programme ?
int a = 2;
int n = 4;
int nCarre;
4 16 int b = 1;

b = a * (b + 2);
nCarre = n * n;
System.out.println(a + ", " + b);
System.out.println("La variable n contient " + n);
System.out.println("Le carre de " + n + " est " + nCarre + ".");
System.out.println("Le double de n est " + 2 * n + ".");

A: a, b

?
Ce qui s'affiche :
La variable n contient 4. B: 1, 2
Le carre de 4 est 16.
Le double de n est 8.
C: 2, 1
▌ D: 2, 6

int a = 2; int a = 2;
int b = 1; int b = 1;

b = a * (b + 2); b = a * (b + 2);

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a a b

2 2 1

4
int a = 2; int a = 2;
int b = 1; int b 2=* (1
1;+ 2) = 2 * 3 = 6

b = a * (b + 2); b = a * (b + 2);

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a b a b

2 1 2 1

int a = 2; int a = 2;
int b 2=* (1
1;+ 2) = 2 * 3 = 6 int b = 1;

b = a * (b + 2); b = a * (b + 2);

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a b a b

2 6 2 6
Affiche:
2, 6

5
Qu’affiche ce programme ?
int a = 5; int a = 5;
int b = a + 3; int b = a + 3;

a = 1; a = 1;

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

A: 5, 4 a

B: 1,
C: 1,
1
4 ? 5
D: 1, 8

int a = 5; int a = 5;
int b = a + 3; int b = a + 3;

a = 1; 5 + 3 = 8 a = 1;

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a b a b

5 8 5 8

6
int a = 5; int a = 5;
int b = a + 3; int b = a + 3;

a = 1; a = 1;

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a b a b

1 8 Affiche: 1 8
1, 8

Qu’affiche ce programme ?
int a = 1; int a = 1;
int b = 2; int b = 2;

a = b; a = b;
b = a; b = a;

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

A: 1, 1

?
a
B: 1, 2
C: 2, 1 1
D: 2, 2

7
int a = 1; int a = 1;
int b = 2; int b = 2;

a = b; a = b;
b = a; b = a;

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a b a b

1 2 1 2

int a = 1; int a = 1;
int b = 2; int b = 2;

a = b; a = b;
b = a; b = a;

System.out.println(a + ", " + b); System.out.println(a + ", " + b);

a b a b

2 2 2 2

8
Supposons qu'on ait déclaré et initialisé deux variables a et b.

int a = 1; Comment échanger leurs valeurs ?


int b = 2;
Les instructions:
a = b;
a = b; b = a;
b = a; ne marchent pas, comme le montre l’exercice précédent.

System.out.println(a + ", " + b);


Solution: utiliser une variable intermédiaire:

int a = 1;
a b int b = 2;
int temp = a;
Affiche:
2, 2 2 2 a = b;
b = temp;

a b a b temp

1 2 1 2 1

int a = 1; int a = 1;
int b = 2; int b = 2;
int temp = a; int temp = a;

a = b; a = b;
b = temp; b = temp;

9
a b temp a b temp

1 2 1 2 2 1

int a = 1; int a = 1;
int b = 2; int b = 2;
int temp = a; int temp = a;

a = b; a = b;
b = temp; b = temp;

a b temp a b temp

2 2 1 2 1 1

int a = 1; int a = 1;
int b = 2; int b = 2;
int temp = a; int temp = a;

a = b; a = b;
b = temp; b = temp;

10
import java.util.Scanner;

class ExempleVariable class DemanderVariable


{ {
public static void main(String[] args) public static void main(String [] args)
{ {
int n = 4; Scanner keyb = new Scanner(System.in);
int nCarre; System.out.println("Entrez une valeur pour n");
int n = keyb.nextInt();
nCarre = n * n;
int nCarre = n * n;
System.out.println("La variable n contient " + n);
System.out.println("Le carre de " + n + " est " + nCarre + "."); System.out.println("La variable n contient " + n);
System.out.println("Le double de n est " + 2 * n + "."); System.out.println("Le carre de " + n + " est " + nCarre + ".");
} System.out.println("Le double de n est " + 2 * n + ".");
} }
}

Lire une valeur au clavier


Lire une valeur au clavier
Il faut d'abord importer la classe Scanner pour la rendre visible au compilateur:
import java.util.Scanner; int n = keyb.nextInt();

On peut maintenant créer un objet Scanner, par exemple: Cette instruction


Scanner keyb = new Scanner(System.in); 1. Arrête le programme momentanément;
2. Attend que l'utilisateur entre une valeur au clavier et appuie sur la touche return;
keyb est une variable qu'on peut utiliser pour demander des valeurs au clavier. 3. Affecte la valeur entrée par l'utilisateur à la variable n,
Par exemple: puis le programme continue.
int n = keyb.nextInt();
nextInt() est une méthode de l'objet Scanner. Il existe une autre méthode pour
demander une valeur de type double:
double x = keyb.nextDouble();

11
Déroulement du programme pas-à-pas Déroulement du programme pas-à-pas
Scanner keyb = new Scanner(System.in); Scanner keyb = new Scanner(System.in);
System.out.println("Entrez une valeur pour n"); System.out.println("Entrez une valeur pour n");
int n = keyb.nextInt(); int n = keyb.nextInt();

int nCarre = n * n; int nCarre = n * n;

System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);

keyb

Ce qui s'affiche: Ce qui s'affiche:


▌ ▌

Déroulement du programme pas-à-pas Déroulement du programme pas-à-pas


Scanner keyb = new Scanner(System.in); Scanner keyb = new Scanner(System.in);
System.out.println("Entrez une valeur pour n"); System.out.println("Entrez une valeur pour n");
int n = keyb.nextInt(); int n = keyb.nextInt();

int nCarre = n * n; int nCarre = n * n;

System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);

keyb keyb

Ce qui s'affiche: Ce qui s'affiche: supposons que l’utilisateur entre la


Entrez une valeur pour n Entrez une valeur pour n valeur 2 au clavier (il faut presser
▌ 2 return une fois la valeur tapée)

12
Déroulement du programme pas-à-pas Déroulement du programme pas-à-pas
Scanner keyb = new Scanner(System.in); Scanner keyb = new Scanner(System.in);
System.out.println("Entrez une valeur pour n"); n System.out.println("Entrez une valeur pour n"); n
int n = keyb.nextInt(); int n = keyb.nextInt();

int nCarre = n * n;
2 int nCarre = n * n;
2
System.out.println("La variable n contient " + n); System.out.println("La variable n contient " + n);

keyb keyb nCarre

4
Ce qui s'affiche: Ce qui s'affiche:
Entrez une valeur pour n Entrez une valeur pour n
2 2
▌ ▌

Déroulement du programme pas-à-pas


Scanner keyb = new Scanner(System.in);
Lecture d'une ligne complète
System.out.println("Entrez une valeur pour n"); n
int n = keyb.nextInt(); Scanner keyb = new Scanner(System.in);
int nCarre = n * n;
2 String s = keyb.nextLine();
System.out.println("Vous avez saisi : " + s);
System.out.println("La variable n contient " + n);
s est une chaine de caractères. Après l'exécution de l'instruction:
keyb nCarre
String s = keyb.nextLine();
4
Ce qui s'affiche: s contient tous les caractères tapés par l'utilisateur, jusqu'à l'appui de return.
Entrez une valeur pour n
2
La variable n contient 2

13
Attention avec nextLine() !
int i = keyb.nextInt();
String s1 = keyb.nextLine();
String s2 = keyb.nextLine();

Si on tape:
25 francs
23 francs
è i contient 25, s1 contient francs, s2 contient 23 francs

Si on tape:
14
euros
43
è i contient 14, s1 est vide, s2 contient euros !

car nextLine() lit ce qui suit 14 jusqu'à la fin de la ligne, c'est-à-dire rien !

14
import java.util.Scanner;

class PremierExempleIf
{
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
Branchements conditionnels System.out.print("Entrez votre nombre:");
int n = scanner.nextInt();

if (n < 5) {
System.out.println("Votre nombre est plus petit que 5.");
} else {
System.out.println("Votre nombre est plus grand ou egal a 5.");
}

System.out.println("fin du programme");
}
}

Mot-clé if Condition

if (n < 5) { if (n < 5) {
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

1
Une accolade ouvrante
Cette instruction sera exécutée si la condition est vraie.
if (n < 5) { if (n < 5) {
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

Une accolade fermante Le mot-clé else

if (n < 5) { if (n < 5) {
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

2
Une accolade ouvrante

if (n < 5) { if (n < 5) {
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

Cette instruction sera exécutée si la condition est fausse.

n
System.out.print("Entrez votre nombre:");
int n = scanner.nextInt();

if (n < 5) {
?
System.out.println("Votre nombre est plus petit que 5.");
} else {
System.out.println("Votre nombre est plus grand ou egal a 5.");
if (n < 5) { }
System.out.println("Votre nombre est plus petit que 5.");
} else { System.out.println("fin du programme");
System.out.println("Votre nombre est plus grand ou egal a 5.");
} Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre:

Une accolade fermante

3
n n
System.out.print("Entrez votre nombre:"); System.out.print("Entrez votre nombre:");
int n = scanner.nextInt(); int n = scanner.nextInt();

if (n < 5) {
? if (n < 5) {
3
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

System.out.println("fin du programme"); System.out.println("fin du programme");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: Entrez votre nombre:
▌ 3

n n
System.out.print("Entrez votre nombre:"); System.out.print("Entrez votre nombre:");
int n = scanner.nextInt(); int n = scanner.nextInt();
?
if (n < 5) {
3 if (n < 5) {
3
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

System.out.println("fin du programme"); System.out.println("fin du programme");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: Entrez votre nombre:
3 3
▌ ▌

4
n n
System.out.print("Entrez votre nombre:"); System.out.print("Entrez votre nombre:");
int n = scanner.nextInt(); int n = scanner.nextInt();

if (n < 5) {
3 if (n < 5) {
3
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

System.out.println("fin du programme"); System.out.println("fin du programme");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: Entrez votre nombre:
3 3
Votre nombre est plus petit que 5. Votre nombre est plus petit que 5.
▌ ▌

n n
System.out.print("Entrez votre nombre:"); System.out.print("Entrez votre nombre:");
int n = scanner.nextInt(); int n = scanner.nextInt();

if (n < 5) {
3 if (n < 5) {
7
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

System.out.println("fin du programme"); System.out.println("fin du programme");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: Entrez votre nombre:
3 7
Votre nombre est plus petit que 5. ▌
fin du programme

5
n n
System.out.print("Entrez votre nombre:"); System.out.print("Entrez votre nombre:");
int n = scanner.nextInt(); int n = scanner.nextInt();
?
if (n < 5) {
7 if (n < 5) {
7
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

System.out.println("fin du programme"); System.out.println("fin du programme");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: Entrez votre nombre:
7 7
▌ Votre nombre est plus grand ou egal a 5.

n
System.out.print("Entrez votre nombre:");
int n = scanner.nextInt();

if (n < 5) {
7
System.out.println("Votre nombre est plus petit que 5.");
} else {
System.out.println("Votre nombre est plus grand ou egal a 5.");
} if (n < 5) {
System.out.println("Votre nombre est plus petit que 5.");
System.out.println("fin du programme"); } else {
System.out.println("Votre nombre est plus grand ou egal a 5.");
Ce qui s'affiche dans la fenêtre Terminal: }
Entrez votre nombre:
7
Votre nombre est plus grand ou egal a 5.
fin du programme

6
Les accolades délimitent un bloc d'instructions Les accolades délimitent un bloc d'instructions
if (n < 5) { if (n < 5) {
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} else { } else {
System.out.println("Votre nombre est plus grand ou egal a 5."); System.out.println("Votre nombre est plus grand ou egal a 5.");
} }

On peut mettre autant d'instructions qu'on veut dans un bloc.


Supposons qu'on veuille aussi afficher la valeur de n quand n est plus petit que 5. Quand un bloc contient une seule instruction, il n'est pas obligatoire d'utiliser des accolades.
Il suffit d'ajouter une instruction dans le premier bloc: On aurait pu écrire:

if (n < 5) { if (n < 5)
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
System.out.println("Votre nombre est " + n); else
System.out.println("Votre nombre est plus grand ou egal a 5.");
} else {
System.out.println("Votre nombre est plus grand ou egal a 5.");
} Néanmoins, une bonne pratique est de toujours utiliser des blocs, même quand il n'y a qu'une seule
instruction.
Ca facilite l'ajout d'instructions.

7
n
System.out.print("Entrez votre nombre: ");
int n = scanner.nextInt();
Une instruction if peut ne pas avoir de deuxième partie.
Par exemple, si on veut ne rien afficher si n est plus grand ou égal à 5, il suffit d'enlever la deuxième if (n < 5) {
3
partie, à partir du else: System.out.println("Votre nombre est plus petit que 5.");
}
if (n < 5) {
System.out.println("Au revoir");
System.out.println("Votre nombre est plus petit que 5.");
}

Ce qui s'affiche dans la fenêtre Terminal:


Entrez votre nombre: 3

n n
System.out.print("Entrez votre nombre: "); System.out.print("Entrez votre nombre: ");
int n = scanner.nextInt(); int n = scanner.nextInt();

if (n < 5) {
3 if (n < 5) {
3
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} }

System.out.println("Au revoir"); System.out.println("Au revoir");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: 3 Entrez votre nombre: 3
Votre nombre est plus petit que 5. Votre nombre est plus petit que 5.
▌ Au revoir

8
n n
System.out.print("Entrez votre nombre: "); System.out.print("Entrez votre nombre: ");
int n = scanner.nextInt(); int n = scanner.nextInt();

if (n < 5) {
7 if (n < 5) {
3
System.out.println("Votre nombre est plus petit que 5."); System.out.println("Votre nombre est plus petit que 5.");
} }

System.out.println("Au revoir"); System.out.println("Au revoir");

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
Entrez votre nombre: 7 Entrez votre nombre: 7
▌ Au revoir

Les choix imbriqués Choix imbriqués: exemple


if (x == y) {
L’instruction if suit donc le schéma:
if (y == z) {
if (condition1) {
System.out.println("Les trois valeurs sont egales.");
... } else {
} else { System.out.println("Seules les deux premieres valeurs sont egales.");
... }
} } else {
if (x == z) {
Les instructions figurant dans les blocs sont absolument quelconques. Il peut donc s’agir d’autres System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
instructions if. } else {
if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales.");
} else {
System.out.println("Les trois valeurs sont differentes.");
}
}
}

9
Choix imbriqués: exemple Supposons:
x y z

if (x == y) { if (x == y) { 1 1 1
if (y == z) { if (y == z) {
System.out.println("Les trois valeurs sont egales."); System.out.println("Les trois valeurs sont egales.");
} else { } else {
System.out.println("Seules les deux premieres valeurs sont egales."); System.out.println("Seules les deux premieres valeurs sont egales.");
} }
} else { Attention à ne pas abuser de cette solution. } else {
if (x == z) { if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales."); System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else { Au-delà de 3 niveaux, le code devient vite illisible! } else {
if (y == z) { if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales."); System.out.println("Seules les deux dernieres valeurs sont egales.");
} else { } else {
System.out.println("Les trois valeurs sont differentes."); System.out.println("Les trois valeurs sont differentes.");
} }
} }
} }

x y z x y z
Supposons: Supposons:
if (x == y) { 1 1 1 if (x == y) { 1 1 1
if (y == z) { if (y == z) {
System.out.println("Les trois valeurs sont egales."); System.out.println("Les trois valeurs sont egales.");
} else { } else {
System.out.println("Seules les deux premieres valeurs sont egales."); System.out.println("Seules les deux premieres valeurs sont egales.");
} }
Les trois valeurs sont egales. est affiché
} else { } else {
if (x == z) { if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales."); System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else { } else {
if (y == z) { if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales."); System.out.println("Seules les deux dernieres valeurs sont egales.");
} else { } else {
System.out.println("Les trois valeurs sont differentes."); System.out.println("Les trois valeurs sont differentes.");
} }
} }
} }

10
x y z x y z
Supposons: Supposons:
if (x == y) { 1 1 1 if (x == y) { 1 1 1
if (y == z) { if (y == z) {
System.out.println("Les trois valeurs sont egales."); System.out.println("Les trois valeurs sont egales.");
} else { } else {
System.out.println("Seules les deux premieres valeurs sont egales."); System.out.println("Seules les deux premieres valeurs sont egales.");
} }
} else { } else {
if (x == z) { if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales."); System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else { } else {
if (y == z) { if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales."); System.out.println("Seules les deux dernieres valeurs sont egales.");
} else { } else {
System.out.println("Les trois valeurs sont differentes."); System.out.println("Les trois valeurs sont differentes.");
} }
} }
} }

x y z x y z
Supposons: Supposons:
if (x == y) { 1 2 2 if (x == y) { 1 2 2
if (y == z) { if (y == z) {
System.out.println("Les trois valeurs sont egales."); System.out.println("Les trois valeurs sont egales.");
} else { } else {
System.out.println("Seules les deux premieres valeurs sont egales."); System.out.println("Seules les deux premieres valeurs sont egales.");
} }
} else { } else {
if (x == z) { if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales."); System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else { } else {
if (y == z) { if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales."); System.out.println("Seules les deux dernieres valeurs sont egales.");
} else { } else {
System.out.println("Les trois valeurs sont differentes."); System.out.println("Les trois valeurs sont differentes.");
} }
} }
} }

11
x y z x y z
Supposons: Supposons:
if (x == y) { 1 2 2 if (x == y) { 1 2 2
if (y == z) { if (y == z) {
System.out.println("Les trois valeurs sont egales."); System.out.println("Les trois valeurs sont egales.");
} else { } else {
System.out.println("Seules les deux premieres valeurs sont egales."); System.out.println("Seules les deux premieres valeurs sont egales.");
} }
} else { } else {
if (x == z) { if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales."); System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else { } else {
if (y == z) { if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales."); System.out.println("Seules les deux dernieres valeurs sont egales.");
} else { } else {
System.out.println("Les trois valeurs sont differentes."); Seules les deuxtrois
System.out.println("Les dernieres
valeursvaleurs sont egales. est affiché
sont differentes.");
} }
} }
} }

x y z x y z
Supposons: Supposons:
if (x == y) { 1 2 2 if (x == y) { 1 2 2
if (y == z) { if (y == z) {
System.out.println("Les trois valeurs sont egales."); System.out.println("Les trois valeurs sont egales.");
} else { } else {
System.out.println("Seules les deux premieres valeurs sont egales."); System.out.println("Seules les deux premieres valeurs sont egales.");
} }
} else { } else {
if (x == z) { if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales."); System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else { } else {
if (y == z) { if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales."); System.out.println("Seules les deux dernieres valeurs sont egales.");
} else { } else {
System.out.println("Les trois valeurs sont differentes."); System.out.println("Les trois valeurs sont differentes.");
} }
} }
} }

12
x y z
Supposons:
if (x == y) { 1 2 2
if (y == z) {
System.out.println("Les trois valeurs sont egales.");
} else {
System.out.println("Seules les deux premieres valeurs sont egales.");
}
} else {
if (x == z) {
System.out.println("Seules la 1ere et la 3eme valeurs sont egales.");
} else {
if (y == z) {
System.out.println("Seules les deux dernieres valeurs sont egales.");
} else {
System.out.println("Les trois valeurs sont differentes.");
}
}
}

13
Les conditions
L’instruction if fait apparaître une condition entre parenthèses

Condition
Conditions if (n < 5) {
System.out.println("Votre nombre est plus petit que 5.");
} else {
System.out.println("Votre nombre est plus grand ou egal a 5.");
}

Attention, la condition est toujours entourée de parenthèses.

Pour l’instant, nous n’avons rencontré qu'une condition simple, n < 5

Nous allons voir maintenant comment s’écrivent les conditions d’une façon générale.

Les conditions simples Les conditions


Attention: simples
L'opérateur pour tester si deux valeurs sont égales s'écrit avec deux
Les opérateurs de comparaison Les opérateurs de comparaison
signes égal ==

Une condition simple compare deux expressions. Une conditionUn seul signe
simple = représente
compare l'affectation
deux expressions.
Elle utilise un opérateur de comparaison, comme < ou > Elle utilise un opérateur de comparaison, comme < ou >
Par exemple, si on veut tester si la variable n est égale à 5, il faut
écrire:
Opérateurs de comparaison du langage Java: Opérateurs de comparaison du langage C++:
if (n == 5)
Opérateur de comparaison Signification Opérateur de comparaison Signification
< inférieur à et non pas: < inférieur à
> if (n = 5)>
supérieur à supérieur à
== égal à == égal à
<= inférieur ou égal à <= inférieur ou égal à
>= supérieur ou égal à >= supérieur ou égal à
!= différent de != différent de

1
int a = 1;
int b = 2;

if (a == b) {
Attention: System.out.println("Cas 1");
Il n'y a pas d'espaces entre les deux } else {
caractères System.out.println("Cas 2");
}

Opérateur de comparaison Signification if (2 * a == b){


< System.out.println("b est egal au double de a.");
inférieur à
}
> supérieur à
== égal à affiche
<= inférieur ou égal à
>= supérieur ou égal à Cas 2
!= différent de b est egal au double de a.

int a = 1; int a = 1;
int b = 2; int b = 2;

if (a != b) { if (a <= b) {
System.out.println("Cas 2"); System.out.println("Cas 3");
} else { } else {
System.out.println("Cas 1"); System.out.println("Cas 4");
} }

if (2 * a != b) { if (2 * a <= b) {
System.out.println("b est different du double de a."); System.out.println("b est superieur ou egal au double de a.");
} }

affiche affiche

Cas 2 Cas 3
b est superieur ou egal au double de a.

2
Les opérateurs logiques Exemple avec l'opérateur logique &&
On peut relier des conditions simples par des opérateurs logiques. n
System.out.println("Entrez un nombre entre 1 et 10:");
L'opérateur logique && (ET): int n = scanner.nextInt();
faux 0
faux
par exemple, la condition Supposons que la valeur
if ((n >= 1) && (n <= 10)) { entrée pour n soit 0
(a < b) && (c < d) System.out.println("correct");
} else {
est vraie uniquement si les deux conditions (a < b) et (c < d) sont toutes les deux vraies. System.out.println("incorrect"); incorrect est affiché
}

Exemple avec l'opérateur logique && Exemple avec l'opérateur logique &&
n n
System.out.println("Entrez un nombre entre 1 et 10:"); System.out.println("Entrez un nombre entre 1 et 10:");
int n = scanner.nextInt(); int n = scanner.nextInt();
faux 12 vrai 5
vrai faux vrai vrai
Supposons que la valeur Supposons que la valeur
if ((n >= 1) && (n <= 10)) { entrée pour n soit 12 if ((n >= 1) && (n <= 10)) { entrée pour n soit 12
System.out.println("correct"); System.out.println("correct");
} else { } else {
System.out.println("incorrect"); incorrect est affiché System.out.println("incorrect"); correct est affiché
} }

3
Les opérateurs logiques Exemple avec l'opérateur logique ||
L'opérateur logique || (OU): System.out.println("Entrez deux valeurs:"); m n
int n = scanner.nextInt();
vrai
par exemple, la condition int m = scanner.nextInt();
vrai 1 -1
(a < b) || (c < d) if ((m >= 0) || (n >= 0)) {
System.out.println("au moins une valeur est positive");
} else {
est vraie si au moins une des deux conditions (a < b) ou (c < d) est vraie.
System.out.println("les deux valeurs sont negatives");
}
Supposons que la valeur entrée pour m soit +1, et la
valeur entrée pour n soit -1

au moins une valeur est positive est affiché

Exemple avec l'opérateur logique || Exemple avec l'opérateur logique ||


System.out.println("Entrez deux valeurs:"); m n System.out.println("Entrez deux valeurs:"); m n
int n = scanner.nextInt();
vrai int n = scanner.nextInt();
faux
int m = scanner.nextInt();
faux vrai -1 1 int m = scanner.nextInt();
faux faux -1 -1
if ((m >= 0) || (n >= 0)) { if ((m >= 0) || (n >= 0)) {
System.out.println("au moins une valeur est positive"); System.out.println("au moins une valeur est positive");
} else { } else {
System.out.println("les deux valeurs sont negatives"); System.out.println("les deux valeurs sont negatives");
} }
Supposons que la valeur entrée pour m soit -1, et la Supposons que la valeur entrée pour m soit -1, et la
valeur entrée pour n soit +1 valeur entrée pour n soit -1

au moins une valeur est positive est affiché les deux valeurs sont negatives est affiché

4
Les opérateurs logiques
L'opérateur logique ! (NON):

par exemple, la condition

!(a < b)

est vraie si (a < b) est fausse, et fausse si (a < b) est vraie.

Nous verrons des exemples d'utilisation de cet opérateur plus loin dans la suite du cours.

5
Erreurs classiques
Le test d'égalité s'écrit ==, et pas =

Erreurs de débutants if (a = 1) // !!!

n'est pas accepté par le compilateur.

Erreurs classiques
if (a == 1); // !!! Si on utilise des accolades même quand il n'y a qu'une instruction dans le bloc, et
System.out.println("a vaut 1"); qu'on écrive le test de la façon suivante:

a vaut 1 est toujours affiché quelle que soit la valeur de a! if (a == 1) {


System.out.println("a vaut 1");
Le point-virgule est considéré comme une instruction, qui ne fait rien.
}
Le code précédent est compris par le compilateur comme:
if (a == 1)
;
l'erreur précédente a beaucoup moins de chance d'arriver.
System.out.println("a vaut 1");

l'instruction System.out.println("a vaut 1"); est donc située après le if.

1
System.out.println("Entrez le premier nombre:");
Erreurs classiques int n = scanner.nextInt();
System.out.println("Entrez le deuxieme nombre:");
Ne pas oublier les accolades, l'indentation ne suffit pas: int p = scanner.nextInt();
if (n < p)
if ((n < p) && (2 * n >= p)) {
System.out.println("n est plus petit que p"); System.out.print("1");
max = p; }
else
System.out.println("n est plus grand ou egal a p"); if ((n < p) || (2 * n >= p)) {
System.out.print("2");
}
génère à la compilation l'erreur:
error: 'else' without 'if' if (n < p) {
if (2 * n >= p) {
System.out.print("3");
Voici une meilleure présentation du code précédent: } else {
if (n < p) System.out.print("4");
}
System.out.println("n est plus petit que p");
} A: 2
?
System.out.println(); B: 24
max = p;
else Qu’affiche ce programme quand l’utilisateur entre 1 et 2 ? C: 123
System.out.println("n est plus grand ou egal a p"); D: 1234

System.out.println("Entrez le premier nombre:"); System.out.println("Entrez le premier nombre:");


int n = scanner.nextInt(); int n = scanner.nextInt();
System.out.println("Entrez le deuxieme nombre:"); System.out.println("Entrez le deuxieme nombre:");
int p = scanner.nextInt(); int p = scanner.nextInt();

if ((n < p) && (2 * n >= p)) { if ((n < p) && (2 * n >= p)) {
System.out.print("1"); System.out.print("1");
} }

if ((n < p) || (2 * n >= p)) { if ((n < p) || (2 * n >= p)) {


System.out.print("2"); System.out.print("2");
} }

if (n < p) { if (n < p) {
if (2 * n >= p) { if (2 * n >= p) {
System.out.print("3"); System.out.print("3");
} else { } else {
System.out.print("4"); System.out.print("4");
} }
} A: 2 } A: 2
? ?
System.out.println(); B: 24 System.out.println(); B: 24
Qu’affiche ce programme quand l’utilisateur entre 1 et 3 ? C: 123 Qu’affiche ce programme quand l’utilisateur entre 2 et 1 ? C: 123
D: 1234 D: 1234

2
Le type boolean
Le type boolean (pour booléen) est le type des conditions.

Il permet de déclarer des variables contenant la valeur d'une condition.

Le type booléen (boolean) Une variable de type booléen est souvent appelée simplement un booléen.

Un booléen ne peut prendre que deux valeurs possibles: true ou false

Exemple:
int a = 1, b = 2;
boolean test1 = (a == b);
boolean test2 = (a < b);

Le type bool Le type bool


Le type boolean (pour booléen) est le type des conditions. Le type boolean (pour booléen) est le type des conditions.

Il permet de déclarer des variables contenant la valeur d'une condition. Il permet de déclarer des variables contenant la valeur d'une condition.

Une variable de type booléen est souvent appelée simplement un booléen. Une variable de type booléen est souvent appelée simplement un booléen.

Un booléen ne peut prendre que deux valeurs possibles: true ou false Un booléen ne peut prendre que deux valeurs possibles: true ou false

Exemple: Exemple: test1


int a = 1, b = 2; int a = 1, b = 2;
boolean test1 = (a == b); boolean test1 = (a == b);
boolean test2 = (a < b); boolean test2 = (a < b);
false

3
Le type bool Le type bool
Le type boolean (pour booléen) est le type des conditions. Le type boolean (pour booléen) est le type des conditions.

Il permet de déclarer des variables contenant la valeur d'une condition. Il permet de déclarer des variables contenant la valeur d'une condition.

Une variable de type booléen est souvent appelée simplement un booléen. Une variable de type booléen est souvent appelée simplement un booléen.

Un booléen ne peut prendre que deux valeurs possibles: true ou false Un booléen ne peut prendre que deux valeurs possibles: true ou false

Exemple: test1 Exemple: test1 test2


int a = 1, b = 2; int a = 1, b = 2;
boolean test1 = (a == b); boolean test1 = (a == b);
boolean test2 = (a < b);
false boolean test2 = (a < b);
false true

On peut initialiser des booléens à l'aide des constantes false et true. On peut initialiser des booléens à l'aide des constantes false et true.

On peut utiliser des booléens comme des conditions. Par exemple: On peut utiliser des booléens comme des conditions. Par exemple:
•  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens; •  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens;
•  on peut utiliser un booléen comme condition dans un if. •  on peut utiliser un booléen comme condition dans un if.

int a = 1, b = 2; int a = 1, b = 2;
c
boolean c = true; boolean c = true;
boolean d = (a == b); boolean d = (a == b); true
boolean e = (d || (a < b)); boolean e = (d || (a < b));

if (e) { if (e) {
System.out.println("e vaut true"); System.out.println("e vaut true");
} }

4
On peut initialiser des booléens à l'aide des constantes false et true. On peut initialiser des booléens à l'aide des constantes false et true.

On peut utiliser des booléens comme des conditions. Par exemple: On peut utiliser des booléens comme des conditions. Par exemple:
•  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens; •  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens;
•  on peut utiliser un booléen comme condition dans un if. •  on peut utiliser un booléen comme condition dans un if.

int a = 1, b = 2; int a = 1, b = 2;
c c d
boolean c = true; boolean c = true;
boolean d = (a == b); true boolean d = (a == b); true false
boolean e = (d || (a < b)); boolean e = (d || (a < b));

if (e) { if (e) {
System.out.println("e vaut true"); System.out.println("e vaut true");
} }

On peut initialiser des booléens à l'aide des constantes false et true. On peut initialiser des booléens à l'aide des constantes false et true.

On peut utiliser des booléens comme des conditions. Par exemple: On peut utiliser des booléens comme des conditions. Par exemple:
•  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens; •  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens;
•  on peut utiliser un booléen comme condition dans un if. •  on peut utiliser un booléen comme condition dans un if.

int a = 1, b = 2; int a = 1, b = 2;
c d c d
boolean c = true; boolean c = true;
boolean d = (a == b); true false boolean d = (a == b); true false
boolean e = (d || (a < b)); boolean e = (d || (a < b));

e
if (e) { if (e) {
System.out.println("e vaut true"); System.out.println("e vaut true");
} } true

5
On peut initialiser des booléens à l'aide des constantes false et true. On peut initialiser des booléens à l'aide des constantes false et true.

On peut utiliser des booléens comme des conditions. Par exemple: On peut utiliser des booléens comme des conditions. Par exemple:
•  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens; •  on peut utiliser des opérateurs logiques (&&, || et !) entre booléens;
•  on peut utiliser un booléen comme condition dans un if. •  on peut utiliser un booléen comme condition dans un if.

int a = 1, b = 2; int a = 1, b = 2;
c d c d
boolean c = true; boolean c = true;
boolean d = (a == b); true false boolean d = (a == b); true false
boolean e = (d || (a < b)); boolean e = (d || (a < b));

e e
if (e) { if (e) {
System.out.println("e vaut true"); System.out.println("e vaut true");
} true } true

Les booléens sont utiles pour de nombreux problèmes, nous rencontrerons


des exemples concrets dans la suite du cours.

6
Les blocs
En Java, les instructions peuvent être regroupées en blocs.

Les blocs d'instructions Les blocs sont identifiés par des délimiteurs de début et de fin : { et }

Exemple:
{
Scanner keyb = new Scanner(System.in);
int i;
double x;

System.out.println("Valeurs pour i et x : ") ;


i = keyb.nextInt();
x = keyb.nextDouble();
System.out.println("Vous avez saisi : i = " + i +
", x = " + x);
}

Les blocs Notion de portée


Les blocs ont en Java une grande autonomie.
‣  Les variables déclarées à l'intérieur d'un bloc sont appelées variables locales
Ils peuvent contenir leurs propres déclarations et initialisation de variables: (au bloc). Elles ne sont accessibles qu'à l'intérieur du bloc.

if (i != 0) { if (i != 0) {
int j = 0; int j = 0;

... ...
j = 2 * i; j = 2 * i;
... ...
} }
// A partir d'ici, on ne peut plus utiliser j // A partir d'ici, on ne peut plus utiliser j

1
Notion de portée Notion de portée

‣  Les variables déclarées à l'intérieur d'un bloc sont appelées variables locales ‣  Les variables déclarées à l'intérieur d'un bloc sont appelées variables locales
(au bloc). Elles ne sont accessibles qu'à l'intérieur du bloc. (au bloc). Elles ne sont accessibles qu'à l'intérieur du bloc.

‣  Les variables déclarées en dehors de main sont de portée globales (à la ‣  Les variables déclarées en dehors de main sont de portée globales (à la
classe). classe).
Elles sont accessibles dans toute la classe. Elles sont accessibles dans toute la classe.

Pour ces variables, on distingue en Java des variables de classes et des


variables d'instance. Bonne pratique: Déclarer les variables au plus près de leur utilisation.

Notion de portée Notion de portée


Déclarer les variables au plus près de leur utilisation La portée d'une variable, c'est l'ensemble des lignes de code où cette variable est
accessible, autrement dit où elle est définie, existe, a un sens.
Par exemple, si la variable j n'est pas utilisée après la condition,
if (i != 0) {
int j = 0;
écrivez: plutôt que:
...
if (i != 0) { int j = 0; j = 2 * i;
int j = 0; if (i != 0) { ...
if (j != 2) {
... ... int k = 0;
j = 2 * i; j = 2 * i;
...
... ... k = 3 * i;
} } ...
}
...
}

2
Portée : règle Portée : cas des itérations

En Java, on ne peut pas utiliser le nom d'une variable La déclaration d'une variable à l'intérieur d'une itération est une déclaration locale
déclarée plus globalement pour déclarer une autre au bloc de la boucle, et aux deux instructions de test et d'incrément:
if (i != 0) {
int j = 0; variable.

... Cela permet d'éviter des ambiguïtés entre noms de for(int i = 0; i < 5; ++i) {
j = 2 * i; variables. System.out.println(i);
... }
if (j != 2) { // A partir d'ici, on ne peut plus utiliser ce i
int j = 0; // interdit
...
j = 3 * i;
...
}
...
}

3
Les boucles conditionnelles Il y a 3 structures de contrôle:
•  les branchements conditionnels,
•  les itérations, et
•  les boucles conditionnelles.

System.out.println("Entrez le nombre de notes");


int nombreDeNotes = clavier.nextInt();
Les itérations, ou boucles for, permettent de répéter une partie du programme.
double somme = 0;
Elles sont utilisées quand le nombre de répétitions est connu avant d'entrer dans la
boucle. if (nombreDeNotes > 0) {
for(int i = 1; i <= nombreDeNotes; ++i) {
System.out.println("Entrez la note numero " + i);
Selon le problème à résoudre, il arrive qu'on ne connaîsse pas combien de fois la
boucle devra être exécutée. double note = clavier.nextDouble();
somme = somme + note;
}
On utilise alors une boucle conditionnelle, ou boucle do..while / while.
System.out.println("Moyenne = " + somme / nombreDeNotes);
}

1
System.out.println("Entrez le nombre de notes");
int nombreDeNotes = clavier.nextInt(); Indique le début
int nombreDeNotes; de la boucle
Comment forcer l'utilisateur à entrer
double somme = 0; une note supérieure à 0 ? do {
System.out.println("Entrez le nombre de notes");
if (nombreDeNotes > 0) { nombreDeNotes = clavier.nextInt();
for(int i = 1; i <= nombreDeNotes; ++i) { } while(nombreDeNotes <= 0);
System.out.println("Entrez la note numero " + i);
double note = clavier.nextDouble(); Corps de la boucle:
somme = somme + note; Il est exécuté au moins une fois dans le
} cas de la boucle do..while
System.out.println("Moyenne = " + somme / nombreDeNotes);
} Condition. Elle est testée juste après chaque exécution du corps de la boucle:
•  si elle est vraie, le corps de la boucle est exécuté une nouvelle fois;
•  si elle est fausse, on sort de la boucle.

Syntaxe de l'instruction do...while L'instruction while...


Il existe également la forme suivante:
do {
bloc while (condition) {
} while(condition); bloc
}
•  Comme pour l'instruction if:
–  La condition peut utiliser des opérateurs logiques.
–  Les parenthèses autour de la condition sont obligatoires. Le principe est similaire à celui de la boucle do…while que nous venons de voir.

La différence est que la condition est testée avant d’entrer dans la boucle. Si la
•  Les instructions à l'intérieur de la boucle do…while sont toujours exécutées au moins une fois.
condition est fausse, les instructions dans la boucle ne sont donc pas exécutées.

•  Si la condition ne devient jamais fausse, les instructions dans la boucle sont répétées
indéfiniment !

2
Exemple Erreurs classiques
Il n'y a pas de ; à la fin de la condition du while...:
int i = 100;
do { while (i < 10); // !!
++i;
Le point-virgule est considéré comme le corps de la boucle,
System.out.println("bonjour"); et l'instruction ++i est après la boucle.
} while (i < 10);
sera interprété comme
affichera une fois bonjour. Si i est inférieur à 10, on entre dans la boucle pour ne jamais
Dans les 2 cas,
en ressortir puisque la valeur de i ne sera jamais modifiée.
la condition i < 10 est fausse. while(i < 10)
;
int i = 100; ++i;
while (i < 10) {
System.out.println("bonjour");
} En revanche, il y a un point-virgule à la fin du do..while:
n'affichera rien. do {
++i;
} while(i < 10);

Quand utiliser la boucle while ?


Quand utiliser la boucle for ? int nombreDeNotes;
Quand le nombre d'itérations (de répétitions) est connu avant d'entrer dans la boucle,
utiliser for: do {
for(int i = 0; i < nombre_d_iterations; ++i) { System.out.println("Entrez le nombre de notes");
nombreDeNotes = clavier.nextInt();
Sinon, utiliser while: } while(nombreDeNotes <= 0);
–  quand les instructions doivent être effectuées au moins une fois, utiliser do…while:
do {
instructions;
} while (condition);
Entrez le nombre de notes:
-2
–  Sinon, utiliser la forme while… il faut entrer un nombre supérieur à 0
while (condition) { Entrez le nombre de notes:
instructions; 5
}

3
int nombreDeNotes; Comment trouver la condition ?
do {
System.out.println("Entrez le nombre de notes"); On veut répéter la boucle tant que le nombre de notes est incorrect,
nombreDeNotes = clavier.nextInt(); le nombre de notes est incorrect si il est inférieur ou égal à 0,
if (nombreDeNotes <= 0) { ce qui donne la condition précédente:
System.out.println("il faut entrer un nombre supérieur a 0");
while (nombreDeNotes <= 0);
}
} while(nombreDeNotes <= 0);

Entrez le nombre de notes:


-2
il faut entrer un nombre superieur a 0
Entrez le nombre de notes:
5

Comment trouver la condition ?


Supposons qu'on veuille écrire un programme qui demande à l'utilisateur de deviner un nombre.
Supposons maintenant qu'on veuille limiter le nombre de notes à 10. Pour simplifier, nous supposerons que le nombre à deviner est toujours 5.

On veut toujours qu'il soit supérieur à 0.


Le programme peut s'écrire ainsi:
Comment trouver la nouvelle condition ?
int nombreADeviner = 5;
int nombreEntre;
On veut répéter la boucle tant que le nombre de notes est incorrect,
le nombre de notes est incorrect si il est inférieur ou égal à 0 ou si il est supérieur à do {
10, System.out.println("Entrez un nombre entre 1 et 10");
nombreEntre = clavier.nextInt();
ce qui donne la nouvelle condition: } while( condition ? );
while (nombreDeNotes <= 0 || nombreDeNotes > 10);
System.out.println("Trouve");

4
Supposons qu'on veuille en plus limiter le nombre d'essais à 3.
On peut ajouter une variable qui va compter le nombre d'essais utilisés:

int nombreADeviner = 5;
la boucle doit être répétée
int nombreADeviner = 5; int nombreEntre; Comment modifier la condition pour que
int nombreEntre; int nombreEssais = 0; la boucle s'arrête quand le nombre
tant que l'utilisateur n'a pas trouvé le nombre à deviner, c'est-à-dire
tantdo
que nombreEntre est différent de nombreADeviner, d'essais dépasse 3 ?
{ do {
la condition est donc:
System.out.println( "Entrez un nombre entre 1 et 10"); System.out.println("Entrez un nombre entre 1 et 10");
nombreEntre = clavier.nextInt(); nombreEntre = clavier.nextInt();
} while(nombreEntre != nombreADeviner); ++nombreEssais;
} while( condition ? );
System.out.println("Trouve");
System.out.println("Trouve");

int nombreADeviner = 5;
int nombreEntre;
int nombreEssais = 0;

do {
System.out.println("Entrez un nombre entre 1 et 10");
int nombreADeviner(5);
la boucle doit être répétée
int nombreEntre;
nombreEntre = clavier.nextInt();
++nombreEssais;
tantint
quenombreEssais(0);
l'utilisateur n'a pas trouvé le nombre à deviner et qu'il reste des essais,
} while(nombreEntre != nombreADeviner && nombreEssais < 3);
c'est-à-dire
tantdoque
{ nombreEntre est différent de nombreADeviner et que Si on veut afficher un message pour indiquer à l'utilisateur s'il a trouvé le nombre ou
cout << "Trouve" << endl;
cout << "Entrez un nombre entre 1 et 10" << endl; si il a épuisé ses essais, on peut ajouter après la boucle:
nombreEssais est inférieur à 3,
cin >> nombreEntre;
la condition est donc:
nombreEssais++;
if (nombreEntre == nombreADeviner) {
System.out.println("Trouve");
} while(nombreEntre != nombreADeviner && nombreEssais < 3);
} else {
System.out.println("Perdu. Le nombre etait " + nombreADeviner);
}

5
int nombreADeviner = 5;
int nombreEntre;
int nombreEssais = 0;

do {
System.out.println("Entrez un nombre entre 1 et 10");
nombreEntre = clavier.nextInt();
++nombreEssais;
} while(nombreEntre != nombreADeviner && nombreEssais < 3);

Attention, si on avait utilisé nombreEssais < 3 comme condition:


if (nombreEssais < 3) {
System.out.println("Trouve");
} else {
System.out.println("Perdu. Le nombre etait " + nombreADeviner);
}
le programme afficherait "Perdu. ..." quand l'utilisateur trouve au troisième essai.

6
Itérations : introduction
Il y a 3 structures de contrôle:
•  les branchements conditionnels,
•  les itérations, et
•  les boucles conditionnelles.

La boucle for Condition:


Une boucle for permet de répéter un nombre donné de fois la même série d'instructions. testée avant l'exécution de chaque tour de boucle.
Si elle est fausse, on sort de la boucle.
Mot-clé for
Par exemple, si on fait:
for(int i = 0; i < 5; ++i) { for(int i = 0; i < 5; ++i) {
System.out.println("le carre de " + i + " vaut " + i * i); System.out.println("le carre de " + i + " vaut " + i * i);
} }

le programme affichera les carrés des 5 premiers entiers: Déclaration et initialisation: Incrémentation:
n'est exécutée qu'une seule fois, exécutée à la fin de chaque tour de boucle. Elle permet
avant d'entrer dans la boucle de changer la valeur du compteur de boucle (ici, la
le carre de 0 vaut 0 variable i).
le carre de 1 vaut 1
le carre de 2 vaut 4 Rappel: ++i; ajoute 1 à la variable i. Cette instruction
le carre de 3 vaut 9 fait la même chose que i = i + 1;
le carre de 4 vaut 16

1
Comme pour le if, les accolades ne sont obligatoires que si plusieurs instructions
doivent être répétées.

for(int i = 0; i < 5; ++i) { Si il n'y a qu'une seule instruction, on peut ne pas utiliser d'accolades:
System.out.println("le carre de " + i + " vaut " + i * i); for(int i = 0; i < 5; ++i)
} System.out.println("i = " + i);

Corps de la boucle: Mais, toujours comme pour le if, il est conseillé de garder les accolades:
Bloc d'instructions qui seront exécutées for(int i = 0; i < 5; ++i) {
à chaque tour de boucle. System.out.println("i = " + i);
}

Pas-à-pas i
La variable i est déclarée et initialisée à 0

for(int i = 0; i < 5; ++i) { for(int i = 0; i < 5; ++i) {


System.out.println("le carre de " + i + " vaut " + i * i); System.out.println("le carre de " + i + " vaut " + i * i);
} }

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
▌ ▌

2
i i

0 0
for(int i = 0; i < 5; ++i) { for(int i = 0; i < 5; ++i) {
System.out.println("le carre de " + i + " vaut " + i * i); System.out.println("le carre de " + i + " vaut " + i * i);
} }

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
▌ le carre de 0 vaut 0

i i

0 1
for(int i = 0; i < 5; ++i) { for(int i = 0; i < 5; ++i) {
System.out.println("le carre de " + i + " vaut " + i * i); System.out.println("le carre de " + i + " vaut " + i * i);
} }

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
le carre de 0 vaut 0 le carre de 0 vaut 0
▌ ▌

3
i i

1 1
for(int i = 0; i < 5; ++i) { for(int i = 0; i < 5; ++i) {
System.out.println("le carre de " + i + " vaut " + i * i); System.out.println("le carre de " + i + " vaut " + i * i);
} }

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
le carre de 0 vaut 0 le carre de 0 vaut 0
le carre de 1 vaut 1 le carre de 1 vaut 1
▌ ▌

i i

4 5
for(int i = 0; i < 5; ++i) { for(int i = 0; i < 5; ++i) {
System.out.println("le carre de " + i + " vaut " + i * i); System.out.println("le carre de " + i + " vaut " + i * i);
} }

Ce qui s'affiche dans la fenêtre Terminal: Ce qui s'affiche dans la fenêtre Terminal:
le carre de 0 vaut 0 le carre de 0 vaut 0
le carre de 1 vaut 1 le carre de 1 vaut 1
le carre de 2 vaut 4 le carre de 2 vaut 4
le carre de 3 vaut 9 le carre de 3 vaut 9
le carre de 4 vaut 16 le carre de 4 vaut 16
▌ ▌

4
Syntaxe de l'instruction for

for(déclaration_et_initialisation; condition; incrémentation) {


for(int i = 0; i < 5; ++i) {
System.out.println("le carre de " + i + " vaut " + i * i);
bloc
}
}
Le programme continue en exécutant les instructions après la boucle.

Ce qui s'affiche dansLa


la variable i n'est déclarée que pour l'intérieur de la boucle.
fenêtre Terminal: •  Si la condition ne devient jamais fausse, les instructions dans la boucle sont
répétées indéfiniment !
le carre de 0 vaut 0
le carre de 1 vautElle
1 ne peut pas être utilisée à l'extérieur de la boucle.
le carre de 2 vaut 4
le carre de 3 vaut 9
le carre de 4 vaut 16

Affichage d’une table de multiplication Affichage d’une table de multiplication


Dans le programme suivant, la même ligne ou presque est répétée 10 fois:
Une constante prend les valeurs de 1 à 10.

System.out.println("Table de multiplication par 5:"); On peut remplacer:

System.out.println("5 multiplie par 1 vaut " + 5 * 1); System.out.println("5 multiplie par 1 vaut " + 5 * 1);
System.out.println("5 multiplie par 2 vaut " + 5 * 2); System.out.println("5 multiplie par 2 vaut " + 5 * 2);
System.out.println("5 multiplie par 3 vaut " + 5 * 3); System.out.println("5 multiplie par 3 vaut " + 5 * 3);
System.out.println("5 multiplie par 4 vaut " + 5 * 4); System.out.println("5 multiplie par 4 vaut " + 5 * 4);
System.out.println("5 multiplie par 5 vaut " + 5 * 5); System.out.println("5 multiplie par 5 vaut " + 5 * 5);
... ...

à il faut utiliser une boucle for pour éviter cette répétition. par
for(int i = 1; i <= 10; ++i) {
System.out.println("5 multiplie par " + i + " vaut " + 5 * i);
}
La variable i prend ici les valeurs de 1 à 10.

5
Que s'affiche-t-il quand on exécute le code :

for(int i = 0; i < 5; ++i) {


System.out.print(i);
if (i % 2 == 0) {
System.out.print("p");
}
System.out.print(" ");
}
System.out.println();

A: 0p 1 2p 3 4p

B: 0p 1 2 3 4

C: 0 1 2p 3 4
?
D: 0p 1p 2p 3p 4p

6
Exemples d'autres formes de boucles for

Itérations : for(int p = 0; p < 10; p += 2) {


...

approfondissements et
la variable p prendra les valeurs de 0, 2, 4, 6, 8 (p += 2 est équivalent à p = p + 2);

exemples for(int k = 10; k > 0; --k) {


...
la variable k prendra les valeurs 10, 9, 8 … jusqu’à 1;

for(int i = 0; i >= 0; ++i) {


...
la condition est toujours vraie (du moins dans le principe).
La boucle est répétée indéfiniment et la variable i prendra toutes les valeurs positives que le type int peut
représenter

Boucles infinies Boucles infinies


Une boucle for peut ne pas s'arrêter, ce qui se produit quand la condition est toujours vraie. Une boucle for peut ne pas s'arrêter, ce qui se produit quand la condition est toujours vraie.
Plusieurs causes sont possibles: Plusieurs causes sont possibles:

1.  On s'est trompé sur la condition: 1.  On s'est trompé sur la condition:
Par exemple: Par exemple:
for(int i = 0; i > -1; ++i) { // !!! for(int i = 0; i > -1; ++i) { // !!!

2.  On s'est trompé sur l'incrémentation:


for(int i = 0; i < 10; ++j) { // !!!
j est incrémenté au lieu de i, i garde donc toujours la valeur 0, et la boucle ne s'arrête pas.

1
Pas de point-virgule (;) à la fin de Attention aux accolades
l'instruction for for(int i = 0; i < 5; ++i)
Les instructions suivantes n'affichent qu'une seule fois la chaine "bonjour": System.out.println("i = " + i);
for(int i = 0; i < 10; ++i); System.out.println("Bonjour");
System.out.println("bonjour");
affiche:
i = 0
Le point-virgule seul est considéré comme une instruction (qui ne fait rien). i = 1
i = 2
Le corps de la boucle est donc constitué de cette instruction qui ne fait rien: i = 3
for(int i = 0; i < 10; ++i) i = 4
Bonjour
;
System.out.println("bonjour"); Interprétation:
for(int i = 0; i < 5; ++i)
i prendra les valeurs de 0 à 10, puis l'ordinateur sortira de la boucle, et exécutera l'instruction System.out.println("i = " + i);
System.out.println("bonjour"); System.out.println("Bonjour");
une seule fois.

Evitez de modifier une variable compteur Moyenne de 4 notes


à l'intérieur d'une boucle for Sans boucle for, en utilisant 5 variables:

Scanner clavier = new Scanner(System.in);


for(int i = 0; i < 10; ++i) {
double somme = 0;
...
if (...) System.out.println("Entrez la note numero 1");
double note1 = clavier.nextDouble();
--i; // !!!
} System.out.println("Entrez la note numero 2");
double note2 = clavier.nextDouble();

1.  Ça ne fera sans doute pas ce que vous voulez: n'oubliez pas que la boucle for, de son System.out.println("Entrez la note numero 3");
côté, incrémente la variable i. double note3 = clavier.nextDouble();

System.out.println("Entrez la note numero 4");


2.  Un relecteur risque de ne pas s'apercevoir que la variable est modifiée également à double note4 = clavier.nextDouble();
l'intérieur de la boucle, et de ne pas comprendre le fonctionnement. somme = note1 + note2 + note3 + note4;

System.out.println("Moyenne = " + somme / 4);

2
Sans boucle for, en n'utilisant que 2 variables: Pour vérifier le programme précédent, supposons que l'utilisateur entre les notes 5, 4, 6 et 4:

double somme = 0; double somme = 0;

System.out.println("Entrez la note numero 1"); System.out.println("Entrez la note numero 1");


double note = clavier.nextDouble(); double note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 2"); System.out.println("Entrez la note numero 2");


somme
note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 3"); System.out.println("Entrez la note numero 3");


note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 4"); System.out.println("Entrez la note numero 4");


note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Moyenne = " + somme / 4); System.out.println("Moyenne = " + somme / 4);

Pour vérifier le programme précédent, supposons que l'utilisateur entre les notes 5, 4, 6 et 4: Pour vérifier le programme précédent, supposons que l'utilisateur entre les notes 5, 4, 6 et 4:

double somme = 0; double somme = 0;


note note
System.out.println("Entrez la note numero 1"); System.out.println("Entrez la note numero 1");
double note = clavier.nextDouble(); double note = clavier.nextDouble();
somme = somme + note; somme = somme + note; 5
System.out.println("Entrez la note numero 2"); System.out.println("Entrez la note numero 2");
somme somme
note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 3"); 0 System.out.println("Entrez la note numero 3"); 0


note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 4"); System.out.println("Entrez la note numero 4");


note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Moyenne = " + somme / 4); System.out.println("Moyenne = " + somme / 4);

3
Pour vérifier le programme précédent, supposons que l'utilisateur entre les notes 5, 4, 6 et 4: Pour vérifier le programme précédent, supposons que l'utilisateur entre les notes 5, 4, 6 et 4:

double somme = 0; double somme = 0;


note note
System.out.println("Entrez la note numero 1"); System.out.println("Entrez la note numero 1");
double note = clavier.nextDouble(); double note = clavier.nextDouble();
somme = somme + note; 4 somme = somme + note; 4
System.out.println("Entrez la note numero 2"); System.out.println("Entrez la note numero 2");
somme somme
note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 3"); 5 System.out.println("Entrez la note numero 3"); 5


note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Entrez la note numero 4"); System.out.println("Entrez la note numero 4");


note = clavier.nextDouble(); note = clavier.nextDouble();
somme = somme + note; somme = somme + note;

System.out.println("Moyenne = " + somme / 4); System.out.println("Moyenne = " + somme / 4);

Pour vérifier le programme précédent, supposons que l'utilisateur entre les notes 5, 4, 6 et 4:

double somme = 0;
Même programme en utilisant une boucle for.
note
System.out.println("Entrez la note numero 1");
double note = clavier.nextDouble();
somme = somme + note; 6
System.out.println("Entrez la note numero 2"); double somme = 0;
somme
note = clavier.nextDouble();
somme = somme + note;
for(int i = 1; i <= 4; ++i) {
System.out.println("Entrez la note numero 3"); 9 System.out.println("Entrez la note numero " + i);
note = clavier.nextDouble();
double note = clavier.nextDouble();
somme = somme + note;
somme = somme + note;
System.out.println("Entrez la note numero 4"); }
note = clavier.nextDouble();
somme = somme + note;
System.out.println("Moyenne = " + somme / 4);
System.out.println("Moyenne = " + somme / 4);

4
Comment modifier le code pour laisser l'utilisateur choisir le nombre de notes ?
note

5
double somme = 0; somme double somme = 0;

for(int i = 1; i <= 4; ++i) { for(int i = 1; i <= 4; ++i) {


System.out.println("Entrez la note numero " + i); 0 System.out.println("Entrez la note numero " + i);
double note = clavier.nextDouble(); double note = clavier.nextDouble();
somme = somme + note; i somme = somme + note;
} }

System.out.println("Moyenne = " + somme / 4);


1 System.out.println("Moyenne = " + somme / 4);

Il y a un bug!

System.out.println("Entrez le nombre de notes"); System.out.println("Entrez le nombre de notes");


int nombre_de_notes = clavier.nextInt(); int nombre_de_notes = clavier.nextInt();

double somme = 0; double somme = 0;

for(int i = 1; i <= nombre_de_notes; ++i) { for(int i = 1; i <= nombre_de_notes; ++i) {


System.out.println("Entrez la note numero " + i); System.out.println("Entrez la note numero " + i);
double note = clavier.nextDouble(); double note = clavier.nextDouble();
somme = somme + note; somme = somme + note;
} }

System.out.println("Moyenne = " + somme / nombre_de_notes); System.out.println("Moyenne = " + somme / nombre_de_notes);

5
Une solution:
Boucles imbriquées
System.out.println("Entrez le nombre de notes"); Reprenons l'exemple précédent de la table de multiplication par 5:
int nombre_de_notes = clavier.nextInt();
for(int i = 1; i <= 10; ++i) {
System.out.println("5 multiplie par " + i + " vaut " + 5 * i);
double somme = 0;
}

if (nombre_de_notes > 0) { Supposons qu'on veuille maintenant afficher toutes les tables de multiplication, de 2 à 10.
for(int i = 1; i <= nombre_de_notes; ++i) {
System.out.println("Entrez la note numero " + i); Il suffit de mettre la boucle précédente dans une autre boucle, et de remplacer le 5 par...ce qu'il
double note = clavier.nextDouble(); faut.
somme = somme + note;
}

System.out.println("Moyenne = " + somme / nombre_de_notes);


}

Boucles imbriquées Boucles imbriquées

for(int j = 2; j <= 10; ++j) { for(int j = 2; j <= 10; ++j) {


for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println("5 multiplie par " + i + " vaut " + 5 * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

affiche 9 fois la table de multiplication par 5 affiche la table de multiplication par 2, puis par 3, jusque 10.

6
j j

for(int j = 2; j <= 10; ++j) { for(int j = 2; j <= 10; ++j) { 2


System.out.println("Table de multiplication par " + j + ": "); System.out.println("Table de multiplication par " + j + ": ");
for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println(j + " multiplie par " + i + " vaut " + j * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

▌ Table de multiplication par 2:


j i j i

for(int j = 2; j <= 10; ++j) { 2 for(int j = 2; j <= 10; ++j) { 2 1


System.out.println("Table de multiplication par " + j + ": "); System.out.println("Table de multiplication par " + j + ": ");
for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println(j + " multiplie par " + i + " vaut " + j * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

Table de multiplication par 2: Table de multiplication par 2:


▌ 2 multiplie par 1 vaut 2

7
j i j i

for(int j = 2; j <= 10; ++j) { 2 1 for(int j = 2; j <= 10; ++j) { 2 2


System.out.println("Table de multiplication par " + j + ": "); System.out.println("Table de multiplication par " + j + ": ");
for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println(j + " multiplie par " + i + " vaut " + j * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

Table de multiplication par 2: Table de multiplication par 2:


2 multiplie par 1 vaut 2 2 multiplie par 1 vaut 2
▌ 2 multiplie par 2 vaut 4

j i j

for(int j = 2; j <= 10; ++j) { 2 10 for(int j = 2; j <= 10; ++j) { 2


System.out.println("Table de multiplication par " + j + ": "); System.out.println("Table de multiplication par " + j + ": ");
for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println(j + " multiplie par " + i + " vaut " + j * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

Table de multiplication par 2: Table de multiplication par 2:


2 multiplie par 1 vaut 2 2 multiplie par 1 vaut 2
2 multiplie par 2 vaut 4 2 multiplie par 2 vaut 4
... ...
2 multiplie par 10 vaut 20 2 multiplie par 10 vaut 20
▌ ▌

8
j j

for(int j = 2; j <= 10; ++j) { 2 for(int j = 2; j <= 10; ++j) { 3


System.out.println("Table de multiplication par " + j + ": "); System.out.println("Table de multiplication par " + j + ": ");
for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println(j + " multiplie par " + i + " vaut " + j * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

Table de multiplication par 2: Table de multiplication par 2:


2 multiplie par 1 vaut 2 2 multiplie par 1 vaut 2
2 multiplie par 2 vaut 4 2 multiplie par 2 vaut 4
... ...
2 multiplie par 10 vaut 20 2 multiplie par 10 vaut 20
▌ Table de multiplication par 3:

j i j i

for(int j = 2; j <= 10; ++j) { 3 1 for(int j = 2; j <= 10; ++j) { 3 1


System.out.println("Table de multiplication par " + j + ": "); System.out.println("Table de multiplication par " + j + ": ");
for(int i = 1; i <= 10; ++i) { for(int i = 1; i <= 10; ++i) {
System.out.println(j + " multiplie par " + i + " vaut " + j * i); System.out.println(j + " multiplie par " + i + " vaut " + j * i);
} }
} }

Table de multiplication par 2: Table de multiplication par 2:


2 multiplie par 1 vaut 2 2 multiplie par 1 vaut 2
2 multiplie par 2 vaut 4 2 multiplie par 2 vaut 4
... ...
2 multiplie par 10 vaut 20 2 multiplie par 10 vaut 20
Table de multiplication par 3: Table de multiplication par 3:
▌ 3 multiplie par 1 vaut 3

9
Que s'affiche-t-il quand on exécute le code :

for(int i = 0; i < 3; ++i) {


for(int j = 0; j < 4; ++j) {

Itérations
if (i == j) {
System.out.print("*");
} else {
System.out.print(j);
A: C:
} *123 ****
} *123 ****

}
System.out.println(""); *123 ****
?
B: D:
012* *123
012* 0*23
012* 01*3

Que s'affiche-t-il quand on exécute le code :

for(int i = 0; i < 3; ++i) {


for(int j = 0; j < i; ++j) {
System.out.print(j);
}
System.out.println("");
}
A: C:
rien
0
01

B: D:
?
0 0123
01 0123
012 0123

1
Rencontre du 5e type

À ce stade du cours, la représentation des données se réduit aux types


Cours d’introduction à la programmation (en Java) élémentaires int, doubleet boolean.

Types avancés I (en Java) Ils permettent de représenter, dans des variables, des concepts simples du monde
modélisé dans le programme :
dimensions, sommes, tailles, expressions logiques, ...
Jamila Sam
Jean-Cédric Chappelier Cependant, de nombreuses données plus sophistiquées ne se réduisent pas à un
Vincent Lepetit objet informatique élémentaire.

Faculté I&C
+ un langage de programmation évolué doit donc fournir le moyen de composer
les types élémentaires pour construire des types plus complexes, les types
composés.

Exemples de données structurées Types de base et types évolués

I Toute variable de type de base stocke directement une valeur :


Âge Nom Taille Âge Sexe x
20 Dupond 1.75 41 M
35 Dupont 1.75 42 M
26 Durand 1.85 26 F 12.98705 double x = 12.98705;

38 Dugenou 1.70 38 M
22 Pahut 1.63 22 F
I Toute variable de type évolué, comme les tableaux ou les chaînes de
caractères (String) que vous allez voir dans ce cours, stocke une référence
(adresse) vers une valeur :
I tableaux v
I structures de données hétérogènes String v = "Welcome";
(par exemple, « un enregistrement » dans le tableau de droite ci-dessus)
I chaînes de caractères ref
"Welcome"
(par exemple, le « nom »)
I ...
Types de base et types évolués (2) Petit exemple introductif
I Toute variable de type de base stocke directement une valeur
I Toute variable de type évolué stocke une référence vers une valeur

+ Attention : ceci a une très grande incidence sur la sémantique des Supposons que l’on souhaite écrire
opérateurs = et == en Java ! Score Écart à la moyenne
un programme de jeu à plusieurs
1000 -1860
+ Cela a aussi un incidence sur l’affichage joueurs.
1500 -1360
2490 -370
I double x = 13.5 veut dire « J’affecte à x la valeur 13.5 »
6450 3590
I String s = "coucou" veut dire « J’affecte à s une référence à la chaîne de ... ...
caractères coucou » Commençons modestement par... deux joueurs.
En clair, si v1 et v2 sont de type évolué :
I v1 = v2 affecte l’adresse de v2 à la variable v1
I v1 == v2 compare l’adresse de v2 avec celle de v1
I System.out.println(v1); affiche l’adresse de v1 (dans le cas général)

Nous y reviendrons . . .

Solution avec les moyens actuels Solution avec les moyens actuels (2)
... System.out.println ("Score Joueur 1:");
Scanner keyb = new Scanner(System.in); int score1 = keyb.nextInt();
System.out.println ("Score Joueur 2:");
// Lecture des donnees et calculs int score2 = keyb.nextInt();
System.out.println ("Score Joueur 1:"); System.out.println ("Score Joueur 3:");
int score1 = keyb.nextInt(); int score3 = keyb.nextInt();
System.out.println ("Score Joueur 2:"); System.out.println ("Score Joueur 4:");
int score2 = keyb.nextInt(); int score4 = keyb.nextInt();
// Calcul de la moyenne System.out.println ("Score Joueur 5:");
double moyenne = (score1 + score2); int score5 = keyb.nextInt();
moyenne /= 2;
// Affichages // calcul de la moyenne
System.out.println("Score Ecart Moyenne"); double moyenne = (score1 + score2 + score3 + score4 + score5);
System.out.println(score1 + " " + (score1 - moyenne)); moyenne /= 5;
System.out.println(score2 + " " + (score2 - moyenne));
...

Comment passer à plus de joueurs ? Comment faire les affichages ?


+ utiliser plus de variables
Solution avec les moyens actuels (3) Solution avec les moyens actuels : limites
System.out.println ("Score Joueur 1:");
int score1 = keyb.nextInt();
System.out.println ("Score Joueur 2:");
int score2 = keyb.nextInt();
...
Mais
System.out.println ("Score Joueur 5:");
int score5= keyb.nextInt(); 1. comment l’écrire (scorei n’est pas correct) ?

// calcul de la moyenne 2. comment faire si on veut considérer 100, 1000... joueurs ?


double moyenne = (score1 + score2 + score3 + score4 + score5);
moyenne /= 5;
3. comment faire si le nombre de joueurs n’est pas connu au départ ?

+ Solution : les tableaux


// Affichages
System.out.println("Score Ecart Moyenne");
for(int i = 1; i <= 5; ++i) {
System.out.println(scorei + " " + scorei - moyenne);
}

Solution avec tableau Les tableaux


System.out.print ("Donnez le nombre de joueurs:");
int n = keyb.nextInt();
if (n > 0) { Un tableau est une collection de valeurs homogènes,
double moyenne = 0;
c’est-à-dire constitué d’éléments qui sont tous du même type.
int scores [] = new int[n];
Exemple : Tableau scores contenant 4 int
// Lecture des scores
for (int i = 0; i < n; ++i) { 1000 1500 2490 6450
System.out.println ("Score Joueur " + i + " :");
scores[i] = keyb.nextInt(); scores[0] scores[1] scores[2] scores[3]
moyenne += scores[i];
} On utilise donc les tableaux lorsque plusieurs variables de même type doivent être
moyenne /= n; // calcul de la moyenne
stockées/mémorisées.
// Affichages On pourra définir des tableaux d’int, de double, de bool, ...
System.out.println(" Score " + " Ecart Moyenne");
for (int i = 0; i < n ; ++i) { ... mais aussi de n’importe quel autre type à disposition
System.out.println(scores[i] + " " + (scores[i] - moyenne)); par exemple des tableaux de tableaux.
}
}
Les différentes sortes de tableaux Les tableaux en Java
Il existe en général quatre sortes de tableaux :
En Java, on utilise :
taille initiale connue a priori ? taille initiale connue a priori ?
non oui non oui
oui ArrayList ArrayList
taille pouvant varier oui 1. 2. taille pouvant varier lors de
l’utilisation du tableau ? tableaux de taille tableaux de taille
lors de l’utilisation non
fixe fixe
du tableau ? non 3. 4.
Dans un premier temps, nous allons nous intéresser aux
Remarques : tableaux de taille fixe
I avec le premier type de tableau (1.), on peut faire tous les autres dont la taille, en Java, peut se décider avant ou pendant l’exécution, mais qui une
+ les autres permettent des optimisations fois choisie ne peut plus varier pendant le déroulement du programme.
I pratiquement aucun langage de programmation n’offre les 4 variantes Viendront, lors du prochain cours, les tableaux dynamiques, dont la taille peut varier
pendant l’exécution du programme.
Déclaration d’un tableau de taille fixe Initialisation d’un tableau de taille fixe (1)
Syntaxe générale : Type des éléments + crochets [].
Si l’on connaît les valeurs de tous les éléments lors de la déclaration du tableau
int[] scores; + une seule instruction de déclaration-initialisation

1. Déclarer le type du tableau


Note : Java autorise la syntaxe équivalente suivante :
2. Indiquer les éléments entre accolades
int scores[]; 3. Séparer les éléments par des virgules

Les crochets indiquent que la variable peut contenir Exemple : avec des littéraux :
plusieurs éléments du type spécifié
int[] scores = {1000, 1500, 2490, 6450};

Il existe deux techniques pour initialiser les éléments : Exemple : avec des expressions :
1. Dans l’instruction de déclaration int[] scores = {(2500 * 10),(4200 * 10)};
2. Dans des instructions séparées

Situation en mémoire Initialisation d’un tableau de taille fixe (2)


Dans le cas général, on ne connaît pas les valeurs
de tous les éléments lors de la déclaration du tableau
Important : Un tableau n’est pas de type de base,
il est donc manipulé via une référence ! On utilise alors plusieurs instructions pour déclarer et initialiser :
1. Déclarer le type du tableau
[0] [1] [2] [3] 2. Construire le tableau avec :
1000 1500 2490 6450 new type [ taille ]
3. remplir le tableau élément par élément
La déclaration-construction d’un tableau peut se faire avec :
int[] scores I deux instructions distinctes :
int[] scores; // declaration
On dit que la variable scores référence (ou pointe vers) un tableau de int. scores = new int[2]; // construction

I une seule instruction :


La variable scores contient une adresse : l’emplacement du tableau en mémoire !
int[] scores = new int[2]; // declaration-
// -construction
Valeurs par défaut Initialisation d’un tableau de taille fixe (3)
Chaque élément d’un tableau reçoit une valeur par défaut
lors de la construction avec new Une fois le tableau déclaré et construit, il faut
le remplir élément par élément :

int 0 int[] scores = new int[4];


scores[0] = 1000;
double 0.0 scores[1] = 1500;
boolean false scores[2] = 2490;
char '\u0000' scores[3] = 6450;
(objet quelconque) (null)
Situation en mémoire : Comme pour le 1er exemple d’initialisation
[0] [1] [2] [3]
[0] [1] [2] [3]
1000 1500 2490 6450
0 0 0 0

int[] scores
int[] scores

Accès direct aux éléments d’un tableau

Le i+1ème élément d’un tableau tab est accessible


au moyen de l’indexation : tab[i]

Attention ! Les indices correspondant aux éléments d’un tableau


de taille T varient entre 0 et T-1
Le 1er élément d’un tableau tab précédemment déclaré est donc
tab[0] et son 10e élément est tab[9]

Attention ! En cas de débordement une exception est lancée par le programme


+ situation d’erreur provoquant l’arrêt du programme si on ne la traite pas
(la gestion des exceptions n’est pas présentée dans ce cours d’introduction)

Il est impératif que l’élément auquel vous voulez accéder existe effectivement !
Affichage d’un tableaux de taille fixe Accès aux éléments d’un tableau (1)

Très souvent, on voudra accéder aux éléments d’un tableau en effectuant une
itération sur ce tableau.
Le code suivant :
Il existe en fait au moins trois façons d’itérer sur un tableau :
double[] t1 = {1.1, 2.2, 3.4} ; I avec les itérations sur ensemble de valeurs
System.out.println(t1);
for(Type element : tableau)
affiche la référence au tableau t1, donc une adresse. + Type est le type des éléments du tableau
I avec une itération for « classique » :
Si l’on veut faire afficher les entrées du tableau référencé par t1, il faut prévoir une
boucle (itération) ! for(int i=0; i < TAILLE; ++i)
+ TAILLE ? ? voir plus loin
I avec des itérateurs (non présenté dans ce cours)

Accès aux éléments d’un tableau (2) Nombre d’éléments d’un tableau
Pour connaître la taille d’un tableau :
I nomTableau.length
Attention, les itérations sur ensemble de valeurs : Exemple :
for(Type element : tableau)
est très simple et élégant mais : int[] scores = {1000, 1500, 2490, 6450};
System.out.println(scores.length); // 4
I ne permet pas modifier le contenu du tableau boolean[] bs = {true, false};
I ne permet d’itérer que sur un seul tableau à la fois : il n’est pas possible de System.out.println(bs.length); // 2
traverser en une passe deux tableaux pour les comparer par exemple
I ne permet l’accès qu’à un seul élément : on ne peut pas par exemple comparer Attention ! length donne le nombre possible d’éléments. Le remplissage effectif
un élément du tableau et son suivant du tableau n’a pas d’importance !
I itère d’un pas en avant seulement.
Exemple :

int[] scores = new int[2];


System.out.println(scores.length); // 2
Erreurs courantes avec les tableaux Erreur : problème d’indice

Attention !
1. Problème d’indice I L’indice est toujours un int
I Il faut respecter les bornes du tableau :
2. Accès avant la construction du tableau
+ Toujours énumération de [0] à [T-1] (où T est la taille du tableau)

(3.) Accès à un élément non initialisé (objets, valeur null) Exemples :

int[] entiers = new int[250];


(4.) Confusion syntaxique tableau/objet entiers[1.0] = 1; // erreur type
entiers[-13] = 2; // erreur borne
entiers[250] = 4; // erreur borne
Les deux derniers types d’erreurs seront exposés après introduction de la notion
d’objet

Erreur : accès avant construction Erreur : accès avant construction


Il est impossible en Java d’accéder à un élément si le tableau n’a pas encore été Il est impossible en Java d’accéder à un élément si le tableau n’a pas encore été
construit. construit.
La construction se fait : La construction se fait :
I Soit en indiquant les valeurs directement dans l’instruction de déclaration I Soit en indiquant les valeurs directement dans l’instruction de déclaration
I Soit en spécifiant la taille avec new type[taille] I Soit en spécifiant la taille avec new type[taille]

Exemple : Exemple :

int[] entiers1 = {1, 2, 3}; // Déclaration-initialisation int[] entiers1 = {1, 2, 3}; // Déclaration-initialisation
entiers1[0] = 4; // OK entiers1[0] = 4; // OK
int[] entiers2; // Déclaration int[] entiers2; // Déclaration
entiers2[0] = 4; // Erreur ! entiers2 = new int[10]; // Initialisation
entiers2[0] = 4;
Types de base / Types évolué (rappel) Types de base / Types évolué (rappel)
a=b
a=b
Type de base Type évolué
Type de base Type évolué
a=2 a = new int[4];
nouveau tableau a=2 a [1] = 3;
a a
3 2 a a
3 2

0 1 3 2 6

b b
3 b b
3

+ Type de base : modifier a ne modifie pas b


+ Type évolué : modifier (l’objet référencé par) a modifie (l’objet référencé par) b
+ Type évolué : modifier la référence a ne modifie pas la référence b

Tableaux : sémantique de l’opérateur = Tableaux : utilisation (rare) de l’opérateur =


// Les tableaux a et b pointent vers deux emplacements
// différents en memoire
int[] a = new int[10]; // tableau de 10 entiers A moins de vouloir deux noms de variables pour le même tableau,
int[] b = new int[10]; // tableau de 10 entiers
il n’y a pas d’intérêt à vouloir assigner un tableau un à autre
for (int i = 0; i < a.length; ++i) { + l’utilisation de l’opérateur = pour les tableaux est donc rare !
a[i] = i; // remplissage du tableau pointé par a
}
b = a; // opérateur = (affectation) Pour avoir deux tableaux distincts a et b qui ont les mêmes valeurs (c’est-à-dire
System.out.println("a[2] vaut " + a[2] + " et b[2] vaut " + b[2]); faire une copie de a dans b) il aurait fallu utiliser :
a[2] = 42;
System.out.println("a[2] vaut " + a[2] + " et b[2] vaut " + b[2]); for(int i = 0; i < a.length; ++i) {
b[i] = a[i];
ce qui affiche : }

a[2] vaut 2 et b[2] vaut 2


a[2] vaut 42 et b[2] vaut 42 Attention : il faut que b.length ≥ a.length !
Les deux tableaux a et b, après l’affectation b=a; pointent vers le même emplacement mémoire ⇒ En
changeant a[2] on change alors implicitement b[2] et inversément !
Le tableau créé pour b : int[] b = new int[10]; n’est donc jamais rempli ni utilisé !
Tableaux : sémantique de l’opérateur == (1) Tableaux : sémantique de l’opérateur == (2)
Pour vérifier l’égalité de contenu des tableaux,
il faut écrire explicitement les tests :

if (a == null || b == null || a.length != b.length) {


L’opérateur a == b teste si les variables a et b référencent System.out.println("contenus différents ou nuls");
}
le même emplacement mémoire. else {
⇒ ce qui est donc le cas lors de l’affectation b = a; int i = 0;
while(i < a.length && (a[i] == b[i])) {
L’opérateur a == b ne teste pas l’égalité des valeurs contenues dans les tableaux ++i;
pointés par a et b ! }
if (i >= a.length) {
System.out.println("contenus identiques");
}
else {
System.out.println("contenus différents")
}
}

Quelques exemples de manipulation de tableaux Quelques exemples de manipulation de tableaux


Soit un tableau déclaré par :

double[] tab = new double[10];

Affichage du tableau : Saisie au clavier des éléments du tableau :


I si l’on n’a pas besoin d’expliciter les indices : I Il est toujours nécessaire d’expliciter les indices :
System.out.print("Le tableau contient : "); for(int i = 0; i < tab.length; ++i) {
for(double element : tab) { System.out.prinln("Entrez l'élément " + i + ":");
System.out.print(element + " "); tab[i] = scanner.nextDouble();
} }
System.out.println();

I si l’on veut expliciter les indices :


for(int i = 0; i < tab.length; ++i) {
System.out.println("L'élément " + i + " vaut " + tab[i]);
}
Tableaux à plusieurs dimensions Tableaux à plusieurs dimensions
Comment déclarer un tableau à plusieurs dimensions ?

+ On ajoute simplement un niveau de [ ] de plus :


Les tableaux multidimensionnels peuvent également être initialisés lors de leur
C’est en fait un tableau de tableaux... déclaration. Il faut bien sûr spécifier autant de valeurs que les dimensions et ceci
pour chacune des dimensions.
Exemples :
double[][] statistiques = Exemple :
new double[nbCantons][nbCommunes];
«tableau[][j]»
int[][] tableau = {
int[][] scores = { 0, 1, 2, 3, 42 }, 0 1 2 3 42

tableau[i]
new int[nbJoueurs][nbParties]; { 4, 5, 6 },
4 5 6
{ 7, 8 },
{ 9, 0, 1 } 7 8
scores[i] est un tableau de nbParties entiers }; 9 0 1
tableau[2][1]
+ scores est bien un tableau de tableaux.
tableau[2] : 7 8
En faisant une analogie avec les mathématiques, un tableau à une dimension représente
donc un vecteur, un tableau à deux dimensions une matrice et un tableau de plus de deux
dimensions un tenseur.

Déclaration-initialisation (1) Déclaration-initialisation (2)


Cas 1 : On connaît tous les éléments lors de la déclaration

int[][] y = { {1, 2}, {3, 4}, {5, 6} }; Cas 2 : On ne connaît pas tous les éléments lors de la déclaration

int[][] y = new int[3][2];


Accès aux éléments de la 1re dimension :
// remplissage à la main
I Type int[]
y[0][0] = 1;
I y[0], y[1] et y[2] y[0][1] = 2;

Accès aux éléments de la 2e dimension : y[1][0] = 3;


y[1][1] = 4;
I Type int
I y[0][0] y[0][1] (1er tableau) y[2][0] = 5;
y[2][1] = 6;
I y[1][0] y[1][1] (2e tableau)
I y[2][0] y[2][1] (3e tableau)
Parcours Parcours
Le moyen le plus naturel de parcourir un tableau multidimensionnel consiste à Le moyen le plus naturel de parcourir un tableau multidimensionnel consiste à
utiliser des boucles for imbriquées : utiliser des boucles for imbriquées :

1. 1re boucle : fait varier le 1er indice 1. 1re boucle : fait varier le 1er indice

2. 2e boucle : fait varier le 2e indice 2. 2e boucle : fait varier le 2e indice

Exemple : Exemple : Variante (tous les éléments de la 1re dimension ayant la même taille)
for(int i = 0; i < y.length; ++i) { System.out.println(y[0].length); // 2
for(int j = 0; j < y[i].length; ++j) { System.out.println(y[1].length); // 2
System.out.println(y[i][j]); System.out.println(y[2].length); // 2
} for (int i = 0; i < y.length; ++i)
} for (int j = 0; j < y[0].length; ++j)
System.out.println (y[i][j]);
Le type String Le type char

Les caractères (constituants d’une chaîne) peuvent aussi se représenter en tant


Les chaînes de caractères Java sont définies par le type String. que tels :
En toute rigueur, ce n’est pas un type comme les types élémentaires mais une classe.
+ le type char
Syntaxe : déclaration d’une chaîne de caractères
String identificateur; I Le caractère s’écrit entre guillemets simples
L’initialisation peut se faire en affectant à la variable un littéral de type String
I un char contient exactement 1 caractère
Exemples : Déclaration et initialisation
char c1 = 'm';
String unNom; char c2 = 'M';
String message = "Bonjour tout le monde !"; char c3 = ' '; // espace
char c5 = '2';

Le type char (2) String : Sémantique des opérateurs = et ==


Un caractère précédé par un « backslash » (\) a une signification spéciale :
I Caractère spécial :

char c5 = '\n'; // Saut de ligne


char c6 = '\t'; // tabulateur Comme pour les tableaux, une variable de type String contient une référence vers
une chaîne de caractères. La sémantique des opérateurs = et == est donc la même
que pour les tableaux :
I Caractère qui risque d’être mal interprété : String chaine = ""; // chaine pointe vers ""
char c7 = '\''; //guillemet simple String chaine2 = "foo"; // chaine2 pointe vers "foo"
char c8 = '\\''; //backslash chaine = chaine2 ; // chaine et chaine2 pointent vers "foo"
(chaine == chaine2) // retourne true

I Sinon, le « backslash » est erroné :

char c9 = '\a';

Error: Invalid escape character


String : Sémantique des opérateurs = et == String : Affichage

Qu’affiche le code suivant ?

String chaine = "Welcome";


Les litteraux de type String occupent une zone mémoire unique System.out.print(chaine);
+ « Pool » des littéraux
Puisque la variable chaine contient une référence à la zone mémoire contenant la
String chaine1 = "foo"; // chaine1 pointe vers le litteral "foo" chaîne "Welcome", il est raisonnable de penser que ce code affiche une adresse
String chaine2 = "foo" ; // chaine2 pointe vers le litteral "foo" (comme pour les tableaux de manière générale) : ce n’est pas le cas !
if (chaine1 == chaine2 ) // true : chaine1 et chaine2 contiennent la même
//adresse + Le code précédent affiche Welcome

+ Pour les String l’affichage est défini de sorte à prendre en compte la référence
pointée plutôt que la référence elle-même. C’est une exception.

Concaténation Concaténation
Les combinaisons suivantes sont possibles pour la concaténation de deux chaînes :

chaine1 + chaine2 produit une nouvelle chaîne associée à la valeur littérale String + String
constituée de la concaténation des valeurs littérales de chaine1 et de chaine2. String + typeDeBase typeDeBase + String

Exemple : constitution du nom complet à partir du nom de famille et du prénom : où String correspond à une variable ou une valeur littérale de type String, et
typeDeBase à une variable ou une valeur littérale de l’un des types de base (char,
String nom;
String prenom; boolean, double, int etc.).
....
nom = nom + " " + prenom;
Exemple revisité (avec char) :
Important ! La concaténation ne modifie jamais les chaînes concaténées. Elle String nom;
effectue une copie de ces chaînes dans une autre zone en mémoire. String prenom;
....
nom = nom + ' ' + prenom;
Concaténation (Non-)Egalité de Strings
Les opérateurs suivants :
Les concaténations de la forme String+char constituent donc un moyen très
pratique pour ajouter des caractères à la fin d’une chaîne. == égalité
!= non-égalité
De même la concaténation char+String permet l’ajout d’un caractère en début de
chaîne.
testent si deux variables String font référence (ou non) à la même zone mémoire
Exemple : ajout d’un ’s’ final au pluriel :
(occupée par une chaîne de caractères).
String reponse = "solution";
//...
Ceci est le cas lorsque les variables de types String ont été initialisées au moyen
if (n > 1) { de littéraux
reponse = reponse + 's';
} Exemple : utilisation de l’opérateur !=

while (reponse != "oui") ....;

(Non-)Egalité de Strings (2) Comparaison de String


String s1 = "abc";
// s1 pointe vers le littéral "abc"
String s2 = "abc";
// idem (donc même zone mémoire que s1)
String s3 = s2; // s3 stocke la même adresse que s2
String s4 = s1 + "";
// s4 contient l'adresse d'une nouvelle chaîne
// (construite par concaténation) chaine1.equals(chaine2) teste si les chaînes de caractères référencées par
System.out.println((s1==s2) && (s2==s3)); // affiche true
System.out.println(s4); // affiche abc
chaine1 et chaine2 sont constituées des mêmes caractères
System.out.println((s1==s4)); // affiche false
String s1 = "abc";
Situation en mémoire : String s2 = "aBc";
"abc" + "" String s4 = s1 + "";

System.out.println(s1.equals(s4)); // true
s1 s3 System.out.println(s1.equals(s2)); // false
s2 "abc"

s4

Comment faire pour comparer les contenus référencés plutôt que les
références ?
+ Traitement spécifique aux String
Les tableaux en Java Les ArrayList
Un tableau dynamique, est une collection
de données homogènes,
dont le nombre peut changer au cours du
En Java, on utilise : déroulement du programme,
par exemple lorsqu’on ajoute ou retire
taille initiale connue a priori ? des éléments au/du tableau.
non oui
oui ArrayList ArrayList Les tableaux dynamiques sont définis en Java par le biais du type
taille pouvant varier lors de
l’utilisation du tableau ? tableaux de taille tableaux de taille ArrayList
non
fixe fixe
Pour les utiliser, il faut tout d’abord importer les définitions associées à l’aide de la
directive suivante :
import java.util.ArrayList;
à placer en tout début de fichier

Déclaration d’un tableau dynamique Initialisation d’un tableau dynamique

Une variable correspondant à un tableau dynamique se déclare de la façon Un tableau dynamique initialement vide (sans aucun élément) s’initialise comme
suivante : suit :
ArrayList<type> identificateur; ArrayList<type> identificateur = new ArrayList<type>();
où identificateur est le nom du tableau et type correspond au type des éléments où identificateur est le nom du tableau et type correspond au type des éléments
du tableau. du tableau.
Le type des éléments doit nécessairement correspondre à un type évolué.
Exemple :
Exemple :
ArrayList<String> tableau = new ArrayList<String>();
ArrayList<String> tableau;
Méthodes spécifiques Méthodes spécifiques
Un certain nombre d’opérations sont directement attachées au type ArrayList. Quelques fonctions disponibles pour un tableau dynamique nommé tableau, de
type ArrayList<type> :
L’utilisation de ces opérations spécifiques se fait avec la syntaxe suivante :
nomDeTableau.nomDeMethode(arg1, arg2, ...); tableau.size() : renvoie la taille de tableau (un entier)
tableau.get(i) : renvoie l’élément à l’indice i dans le tableau (i est un entier
Exemple : compris entre 0 et tableau.size() - 1)
ArrayList<String> prenoms = new ArrayList<String>(); tableau.set(i, valeur) : affecte valeur à la case i du tableau (cette case doit
avoir été créée au préalable)
System.out.println(prenoms.size()); // affiche 0

Méthodes spécifiques Méthodes spécifiques


Quelques fonctions disponibles pour un tableau dynamique nommé tableau, de Quelques fonctions disponibles pour un tableau dynamique nommé tableau, de
type ArrayList<type> : type ArrayList<type> :
tableau.isEmpty() : détermine si tableau est vide ou non (boolean). tableau.remove(i) : supprime l’élément d’indice i
tableau.clear() : supprime tous les éléments de tableau (et le transforme donc tableau.add(valeur) : ajoute le nouvel élément valeur à la fin de tableau. Pas de
en un tableau vide). Pas de (type de) retour. retour.
Exemple de quelques manipulations de base Que faire pour des types de base ?
import java.util.ArrayList;

class ArrayListExemple {
public static void main(String[] args){
ArrayList<String> liste = new ArrayList<String>(); En Java, à chaque type de base correspond un type évolué prédéfini :

liste.add("un"); I Integer est le type évolué correspondant à int


liste.add("deux"); I Double est le type évolué correspondant à double
for(String v : liste) { I etc.
System.out.print(v + " ");
} + Utiles dans certains contextes (typiquement les ArrayList)
System.out.println(liste.get(1));
+ La conversion du type de base au type évolué se fait automatiquement
liste.set(0, "premier");

}
}
}

Exemple Exemple
Ecrivons un programme qui (ré)initialise un tableau dynamique d’entiers en les Ecrivons un programme qui (ré)initialise un tableau dynamique d’entiers en les
demandant à l’utilisateur, qui peut demandant à l’utilisateur, qui peut
I ajouter des nombres strictement positifs au tableau I ajouter des nombres strictement positifs au tableau

I recommencer au début en entrant 0 I recommencer au début en entrant 0


I effacer le dernier élément en entrant un nombre négatif
I effacer le dernier élément en entrant un nombre négatif
Saisie de 3 valeurs : ArrayList<Integer> vect = new ArrayList<Integer>();
Entrez la valeur 0 : 5
Entrez la valeur 1 : 2 System.out.println("Donnez la taille voulue : ");
Entrez la valeur 2 : 0 int taille = scanner.nextInt();
Entrez la valeur 0 : 7 System.out.println("Saisie de " + taille + " valeurs :");
Entrez la valeur 1 : 2 while (vect.size() < taille) {
Entrez la valeur 2 : -4 System.out.println("Entrez la valeur " + vect.size() + " : ");
Entrez la valeur 1 : 4 int val = scanner.nextInt();
Entrez la valeur 2 : 12 if ((val < 0) && (!vect.isEmpty())) { vect.remove(vect.size() - 1); }
else if (val == 0) { vect.clear(); }
–> 7 4 12 else if (val > 0) { vect.add(val); }
}
Comparaison d’éléments
Attention : les éléments d’un tableau dynamique sont toujours des références
+ Comparaison au moyen de equals

ArrayList<Integer> tab = new ArrayList<Integer>();

tab.add(2000);
tab.add(2000);

System.out.println(tab.get(0) == tab.get(1)); // false

System.out.println((tab.get(0)).equals(tab.get(1))); // true
(Non-)Egalité de Strings (Non-)Egalité de Strings (2)
String s1 = "abc";
// s1 pointe vers le littéral "abc"
Les opérateurs suivants : String s2 = "abc";
// idem (donc même zone mémoire que s1)
String s3 = s2; // s3 stocke la même adresse que s2
String s4 = s1 + "";
// s4 contient l'adresse d'une nouvelle chaîne
== égalité // (construite par concaténation)
System.out.println((s1==s2) && (s2==s3)); // affiche true
!= non-égalité System.out.println(s4); // affiche abc
System.out.println((s1==s4)); // affiche false
testent si deux variables String font référence (ou non) à la même zone mémoire Situation en mémoire :
(occupée par une chaîne de caractères).
"abc" + ""
Ceci est le cas lorsque les variables de types String ont été initialisées au moyen
de littéraux s1 s3
s2 "abc"
Exemple : utilisation de l’opérateur != s4
while (reponse != "oui") ....; Comment faire pour comparer les contenus référencés plutôt que les
références ?
+ Traitement spécifique aux String

Comparaison de String

chaine1.equals(chaine2) teste si les chaînes de caractères référencées par


chaine1 et chaine2 sont constituées des mêmes caractères

String s1 = "abc";
String s2 = "aBc";
String s4 = s1 + "";

System.out.println(s1.equals(s4)); // true
System.out.println(s1.equals(s2)); // false
Les char d’un String Les chars d’un String (2)
I L’instruction chaine.charAt(index) donne le caractère occupant la position
index dans la String chaine
I L’instruction chaine.indexOf(caractere) donne la position de la première
occurence du char caractere dans la String chaine, et -1 si caractere n’est Exercice : qu’affichera le programme suivant :
pas dans chaine. String essai = "essai";
I chaine1.length() donne la taille (c’est-à-dire le nombre de caractères) de String test = "";
chaine1. Attention : il y a une paire de parenthèses ; différent des tableaux ! for (int i = 1; i <= 3; ++i) {
test = test + essai.charAt(6-2*i);
Exemple : test = essai.charAt(i) + test;
}
String s1 = "abcmbx"; System.out.println(test);
int longueur = s1.length(); // 6
char c1 = s1.charAt(0); // a
char c2 = s1.charAt(longueur - 1); // x
int i = s1.indexOf('b'); // 1

+ Les caractères sont numérotés comme les éléments d’un tableau (à partir de 0)

Pas de nextChar() dans la classe Scanner ! ? Littéraux introduits par l’utilisateur

Un littéral introduit par l’utilisateur suite à une instruction de lecture n’est pas dans
le pool des littéraux
Pour récupérer un caractère (char) avec la classe Scanner, il faut faire : Pour qu’il y soit, il faut l’y mettre explicitement au moyen de intern
// Lire la ligne qui contient un caractère Exemple
Scanner keyb = new Scanner(System.in);
Scanner s = new Scanner(System.in);
String s = keyb.nextLine();
String response;
do {
// Prendre comme caractère le premier élément de la String
response = s.nextLine();
char c = s.charAt(0);
//on met le littéral lu dans le pool
response = response.intern();
System.out.println("Read: " + response);
// sans le intern, la boucle ne s'arrête pas!
} while (response != "oui");
Traitements spécifiques aux chaînes replace
Nous avons vu que certains traitements sont spécifiques aux String.
Ils s’utilisent en fait tous avec la syntaxe particulière suivante :
nomDeChaine.nomDeTraitement(arg1, arg2 ...); chaine.replace(char1, char2) : construit une nouvelle chaîne valant chaine où
char1 est remplacé par char2.
Ces traitements s’appellent des méthodes en Java.
Exemple :
+ Ils produisent toujours une nouvelle chaîne de caractères String exemple = "abracadabra";
String avecDesEtoiles = exemple.replace(’a’, ’*’);

construit la nouvelle chaîne "*br*c*d*br*".


exemple vaut toujours "abracadabra".

substring

chaine.substring(position1, position2) : donne la sous-chaîne comprise


entres les indices de position1 (compris) et position2 (non-compris)
Exemple :
String exemple = "anticonstitutionnel";
String racineMot = exemple.substring(4,16);

construit la nouvelle chaîne "constitution".


Notion de réutilisabilité
Pour l’instant : un programme est une séquence d’instructions
+ mais sans partage des parties importantes ou utilisées plusieurs fois
Cours d’introduction à la programmation (en Java)
Si une tâche, par exemple :
Fonctions/Méthodes
do {
System.out.println("Entrez un nombre entre 1 et 100 : ");
Jamila Sam i = clavier.nextInt();
} while ((i < 1) or (i > 100));
Jean-Cédric Chappelier
Vincent Lepetit doit être exécutée à plusieurs endroits dans un plus gros programme

Faculté I&C + recopie ? NON !


Bonne pratique : Ne jamais dupliquer de code en programmant :
Jamais de « copier-coller » !
+ Ce que vous voudriez recopier doit être mis dans une fonction

Notion de réutilisabilité (2) Exemple de fonction

Pourquoi ne jamais dupliquer du code (copier/coller) :


Cela rend le programme
I inutilement long int score (double points, double tempsJeu)
{
I difficile à comprendre int leScore = 0;
if (tempsJeu != 0) {
I difficile à maintenir : leScore = points / tempsJeu;
reporter chaque modification dans chacune des copies }
return leScore;
}
Tout bon langage de programmation fournit donc des moyens pour permettre
la réutilisation de portions de programmes.

+ les fonctions
Notion de réutilisabilité : illustration Notion de réutilisabilité : illustration

for for for

if if if
...

...

...
do { do { do {
z=f(u,v,t); do {
f

...
} while } while } while } while
...

...
for

...
for for
...

...

Fonction (en programmation) Terminologie


fonction = portion de programme réutilisable ou importante en soi

Plus précisément, une fonction est un objet logiciel caractérisé par :


un corps : la portion de programme à réutiliser ou mettre en évidence, qui a
justifié la création de la fonction ; Dans les langages uniquement orienté-objet, comme c’est le cas de Java,
un nom : par lequel on désignera cette fonction ; le terme de « méthode » est généralement utilisé à la place de celui de « fonction ».
des paramètres : (les « entrées », on les appelle aussi « arguments ») ensemble + C’est ce terme que nous utiliserons désormais
de variables extérieures à la fonction dont le corps dépend pour
fonctionner ;
un type et une valeur de retour : (la « sortie ») ce que la fonction renvoie au reste
du programme

L’utilisation de la fonction dans une autre partie du programme se nomme un appel


de la fonction.
Les « 3 facettes » d’une méthode Exemple complet
I Résumé / Contrat (« entête ») class Exemple
I Création / Construction (« définition ») {
private static Scanner clavier= new Scanner(System.in);
I Utilisation (« appel ») public static void main(String[] args)
{
programmeur programmeur double note1 = 0.0;
concepteur/développeur double note2 = 0.0;
utilisateur
System.out.println("Entrez vos deux notes : ");
note1 = clavier.nextDouble();
accord note2 = clavier.nextDouble();
System.out.println("Votre moyenne est : "
+ moyenne(note1, note2)));
} appel
appel entête définition static double moyenne(double x, double y) entête
z = f(2*u, v+3); double f(double x, double f(double a, double b) { définition
double y) { return (x + y) / 2.0;
... }
}

double moyenne (double x, double y)


Évaluation d’un appel de méthode { Évaluation d’un appel de méthode (résumé)
return (x + y) / 2.0;
} L’évaluation de l’appel
Que se passe-t-il lors de l’appel suivant :
f(arg1, arg2, ..., argN)
z = moyenne( 1.5 + 0.8, 3.4 * 1.25 ); d’une méthode définie par
1. évaluation des expressions passées en arguments : typeR f(type1 x1, type2 x2, ..., typeN xN) { ... }
1.5 + 0.8 −→ 2.3 s’effectue de la façon suivante :
3.4 * 1.25 −→ 4.25 x
1. les expressions arg1, arg2, ..., argN passées en argument sont évaluées
2. les valeurs correspondantes sont affectées aux paramètres x1, x2, ..., xN de la
2. affectation des paramètres : copie
méthode f (variables locales au corps de f)
x = 2.3
2.3 Concrètement, ces deux premières étapes reviennent à faire :
y = 4.25 2.3
3. exécution du corps de la méthode : x1 = arg1, x2 = arg2, ..., xN = argN
rien dans ce cas (corps réduit au simple return) 3. le programme correspondant au corps de la méthode f est exécuté
4. évaluation de la valeur de retour (expression derrière return) 4. l’expression suivant la première commande return rencontrée est évaluée...
(x + y) / 2.0 −→ 3.275 5. ...et retournée comme résultat de de l’appel :
cette valeur remplace l’expression de l’appel, i.e. l’expression
5. replacement de l’expression de l’appel par la valeur retournée :
f(arg1, arg2, ..., argN)
z = 3.275;
Évaluation d’un appel de méthode (résumé) Appel : autre exemple
L’évaluation de l’appel d’une méthode s’effectue de la façon suivante :
1. les expressions passées en argument sont évaluées
2. les valeurs correspondantes sont affectées aux paramètres de la méthode Une méthode peut appeler une autre méthode.
3. le corps de la méthode est exécuté
void afficheScore(int joueur, double points, double temps)
4. l’expression suivant la première commande return rencontrée est évaluée... {
5. ...et retournée comme résultat de de l’appel : System.out.println(" Joueur " + joueur
+ score(points, temps) + " points");
cette valeur remplace l’expression de l’appel }

Les étapes 1 et 2 n’ont pas lieu pour une méthode sans arguments. int score (double points, double tempsJeu)
{ // ... comme avant ... }
Les étapes 4 et 5 n’ont pas lieu pour une méthode sans valeur de retour (void).

Appel : résumé Résumé du jargon

L’évaluation de l’appel d’une méthode peut être schématisé de la façon suivante : « Appeler la méthode f » = utiliser la méthode f : x = 2 * f(3);

« 3 est passé en argument » = (lors d’un appel) la valeur 3 est copiée dans un
static double g() { paramètre de la méthode :
x = 2 * f(3);
int y, z; static int f(int x) {
...
... « la méthode retourne la valeur de y » = l’expression de l’appel de la méthode sera
. . . z = f(y) . . .
|{z} ... remplacée par la valeur retournée
... return . . . ;
return y;
} } }
...
x = 2 * f(3);
static int f{. . . }
Autres exemples : « cos(0) retourne le cosinus de 0 », « cos(0) retourne 1 ».
Le passage des arguments (1) Le passage des arguments (2)
Considérons la situation suivante (pseudo-code) : Java ne manipule pas les types élémentaires comme les types évolués :
static void methode(Type v) { Modifier v pour un type élémentaire n’a qu’une seule interprétation possible :
// traitement modifiant v v
}

// ailleurs, dans le programme principal,


// par exemple: 12.98705

Type v1 = .. ; // initialisation de v1
methode(v1);
Pour un type évolué :
// v1 EST-ELLE MODIFIEE ICI OU NON???
v

En programmation de façon générale, on dira que :


I L’argument v est passé par valeur si methode ne peut pas modifier v1 : v est
une copie locale de v1. ref
"Welcome"
I L’argument v est passé par référence si methode peut modifier v1
?
Mais que veut dire «modifier v» ? ?

Le passage des arguments (2) Passage d’argument par valeur : schéma

Il y a donc deux questions à poser au lieu d’une : En Java, il n’existe que le passage par valeur : une méthode travaille toujours sur
une copie de la valeur qui lui est passée en paramètre
static void methode(Type v) { // Type :type EVOLUÉ
// traitement modifiant l'objet référencé par v
// traitement modifiant v lui même (référence) val x
} 1
// ailleurs:
Type v1 = ..; // initialisation de v1 copie
methode(v1);
//1. v1 est-elle modifiée ici?
//2. l'objet référencé par v1 est-il modifié 1
// ici?
Passage par valeur : type élémentaire Passage par valeur : type évolué
static void methode(Type v) { // Type :type EVOLUÉ
// traitement modifiant l'objet référencé par v
// traitement modifiant v lui même (référence)
static void methode(Type v) { }
// traitement modifiant v // ailleurs:
} Type v1 = ..; // initialisation de v1
methode(v1);
// ailleurs, dans le programme principal, //1. v1 est-elle modifiée ici?
// par exemple: //2. l'objet référencé par v1 est-il modifié
Type v1 = .. ; // initialisation de v1 // ici?
methode(v1);
// v1 EST-ELLE MODIFIEE ICI OU NON??? I On a toujours un passage par valeur donc la référence v est une copie de v1.
I Cependant, Type étant évolué, l’argument qui est donné à methode lors de
+ Si Type est un type élémentaire
la réponse à la question dans le code est NON !! l’appel methode(v1) est une copie de la référence à v1 (son adresse) : l’objet
pointé par v est le même que l’objet pointé par v1. Toute modification faite
sur l’objet référencé via v est donc visible via v1 !

+ La réponse à la question 2 est donc OUI (et reste non pour la question 1)

Exemple de passage par valeur (type élémentaire) Type évolué : modification de la référence
public static void main(String[] args) { public static void main(String[] args) {
int val = 1; int[] tab = {1};
m(val); m(tab); // tab (référence)
System.out.println(" val=" + val); // PASSAGE PAR VALEUR AUSSI
} System.out.println(" tab[0]= " + tab[0]);
}
static void m(int x) { static void m(int[] x) {
x = x + 1; int[] t = {100};
System.out.print(" x=" + x); x = t; //Modification de la référence
} //(on met une autre adresse dans x)
System.out.print("x[0]= " + x[0]);
}
L’exécution de ce programme produit l’affichage :
x=2 val=1
L’exécution de ce programme produit l’affichage :
Ce qui montre que les modifications effectuées à l’intérieur de la méthode m() x[0]= 100 tab[0]= 1
ne se répercutent pas sur la variable extérieure val associée au paramètre x et
Les modifications faites dans la méthode sur la référence elle-même ne sont pas
passée par valeur.
visibles à l’extérieur de la méthode !
Type évolué : modification de l’objet référencé Entête
Toute méthode est caractérisée par un entête
public static void main(String[] args) {
int[] tab = {1};
m(tab); I nom
System.out.println(" tab[0]= " + tab[0]); I paramètres
}
static void m(int[] x) { I type de (la valeur de) retour
x[0] = 100; // modification de l'objet
liste de paramètres
// référencé par x z }| {
System.out.print("x[0]= " + x[0]); Syntaxe : type nom ( type1 id_param1 , ..., typeN id_paramN )
}
Au niveau de ce cours, on ajoutera le mot clé static au début de chaque entête.
L’exécution de ce programme produit l’affichage : Mais deviendra une exception dans le cours « Programmation Orientée Objet ».
x[0]= 100 tab[0]= 100
Les modifications faites dans la méthode sur l’objet référencé restent visibles à Exemples d’entêtes :
l’extérieur de la méthode ! static double moyenne(double x, double y)
(on a copié dans x la référence tab : x et tab pointent sur le même tableau.)
static int nbAuHasard()

Entête – Bonnes pratiques Définition des méthodes


La définition d’une méthode sert, comme son nom l’indique, à définir ce que fait la
I Une méthode ne doit faire que ce pour quoi elle est prévue méthode :
Ne pas faire des choses cachées («effets de bords») ni modifier de variables I spécification du corps de la méthode
extérieures (non passées comme arguments)
Syntaxe : type nom ( liste de paramètres )
I Choisissez des noms pertinents pour vos méthodes et vos paramètres {
instructions du corps de la méthode;
Cela augmente la lisibilité de votre code (et donc facilite sa maintenance).
return expression;
}
+ Il est en particulier très important que le nom représente bien ce que doit faire la
méthode Exemple :
I Commencez toujours par écrire l’entête de votre méthode : static double moyenne (double x, double y)
{
Demandez-vous ce qu’elle doit recevoir et retourner. return (x + y) / 2.0;
}
Corps de méthode Remarques sur l’instruction return (1/4)
Le corps de la méthode est donc un bloc
dans lequel on peut utiliser les paramètres de la méthode (en plus des variables qui Il est possible de placer plusieurs instructions return dans une même méthode.
lui sont propres).
Par exemple, une méthode déterminant le maximum de deux valeurs peut s’écrire
La valeur retournée par la méthode avec une instruction return : ou deux :
est indiquée par l’instruction : static double moyenne (double x, double y)
{ static double max2(double a, double b) static double max2(double a, double b)
return expression; { {
return (x + y) / 2.0;
où l’expression a le même type que } double m; if (a > b) {
if (a > b) { return a;
celui retourné par la méthode. m = a; } else {
} else { return b;
L’instruction return fait deux choses: m = b; }
} }
I elle précise la valeur qui sera fournie par la méthode en résultat
return m;
I elle met fin à l’exécution des instructions de la méthode. }

L’expression après return est parfois réduite à une seule variable


ou même à une valeur littérale, mais ce n’est pas une nécessité.

Remarques sur l’instruction return (2/4) Remarques sur l’instruction return (3/4)

return doit être la toute dernière instruction exécutée:


Le type de la valeur retournée doit correspondre au type dans l’en-tête :
static double lire() {
static double bidon() { System.out.print("Entrez un nombre: ");
boolean b = true; Scanner keyb = new Scanner(System.in);
return b; // Erreur double n = keyb.nextDouble();
} return n;
System.out.println(); // Erreur
}
Remarques sur l’instruction return (4/4) Méthodes sans valeur de retour
Le compilateur doit être sûr de toujours pouvoir exécuter un return: Quand une méthode ne doit fournir aucun résultat (on appelle de telles méthodes des
« procédures ») :
static double lire() {
System.out.print("Entrez un nombre: "); + définir une méthode sans valeur de retour
Scanner keyb = new Scanner(System.in);
double n = keyb.nextDouble(); On utilise alors le type particulier void comme type de retour.
if (n > 0) {
return n; Dans ce cas la commande de retour return est optionnelle :
} I soit on ne place aucun return dans le corps de la méthode
// Erreur : pas de return si n <= 0 ! I soit on utilise l’instruction return sans la faire suivre d’une expression: return;
}

static double lire() { Exemple : static void afficheRacine(double a)


Scanner keyb = new Scanner(System.in); {
double n = 0.0; if (a < 0.0) {
do { return; /* Grâce à ce return, on quitte la fonction avant *
System.out.print("Entrez un nombre strictement positif : "); * de calculer sqrt(a) si a est négatif. */
n = keyb.nextDouble(); }
} while (n <= 0.0); System.out.println(Math.sqrt(a));
return n; // il n'est pas nécessaire de mettre un return ici
} }

Méthodes sans paramètre La méthode main


Il est aussi possible de définir des méthodes sans paramètre.
Il suffit, dans l’entête, d’utiliser une liste de paramètres vide : ()

Exemple : private static Scanner clavier = new Scanner(System.in);


main est aussi une méthode avec un nom et un entête imposés.

public static void main(String[] args) Par convention, tout programme Java doit avoir une méthode main, qui est appelée
{ automatiquement quand on exécute le programme.
int val = saisieEntier();
System.out.println(val);
} L’entête autorisée pour main est :

static int saisieEntier() public static void main(String[] args)


{
int i;
System.out.println("entrez un entier: ");
i = clavier.nextInt();
return i;
}
Pour résumer : Méthodologie pour construire une méthode Pour résumer : Méthodologie pour construire une méthode
1. clairement identifier ce que doit faire la méthode
(ce point n’est en fait que conceptuel, on n’écrit aucun code ici !)
+ ne pas se préoccuper ici du comment, mais bel et bien du quoi ! 3. quel type de retour ?
Les instructions dans le corps de la méthode dont la finalité n’est pas le calcul de
la valeur de retour, ou qui modifient des objets extérieurs à la méthode (non + que doit « retourner » la méthode ?
passés en paramètre), sont appelées des « effets de bord ». Se poser ici la question (pour une méthode nommée f) :
est-ce que cela a un sens d’écrire :
2. quels arguments ? z = f(....);
+ que doit recevoir la méthode pour faire ce qu’elle doit ? Si oui + le type de z est le type de retour de f
Si non + le type de retour de f est void
4. (maintenant, et seulement maintenant) Se préoccuper du comment :
comment faire ce que doit faire la méthode ?
+ c’est-à-dire écrire le corps de la méthode

La surcharge de méthodes La surcharge de méthodes : exemple

static void affiche(int x) {


En Java , il est de ce fait possible de définir plusieurs méthodes de même nom si System.out.println("entier : " + x);
ces méthodes n’ont pas les mêmes listes de paramètres : nombre ou types de }
static void affiche(double x) {
paramètres différents. System.out.println("reel : " + x);
}
Ce mécanisme, appelé surcharge des méthodes, est très utile pour écrire des static void affiche(int x1, int x2) {
méthodes « sensibles » au type de leurs arguments System.out.println("couple : " + x1 + "," + x2);
}
c’est-à-dire des méthodes correspondant à des traitements de même nature mais
s’appliquant à des entités de types différents.
affiche(1), affiche(1.0) et affiche(1,1) produisent alors des affichages
différents.
Cours d’introduction à la programmation (en Java)
Programmer un Puissance 4

Jamila Sam
Jean-Cédric Chappelier
Vincent Lepetit

Faculté I&C
Le jeu

| | | | | | | |
| | | | | | | |
| | | |X| | | |
| | |X|O|O|X|O|
| | |O|X|X|X|O|
| |O|O|X|X|O|X|
==1=2=3=4=5=6=7==

Joueur O : entrez un numéro de colonne


5

| | | | | | | |
| | | | | | | |
| | | |X|O| | |
| | |X|O|O|X|O|
| | |O|X|X|X|O|
| |O|O|X|X|O|X|
==1=2=3=4=5=6=7==

Le joueur O a gagne !
Développement

1. N’essayez pas d’écrire tout le programme en une seule fois !


I Décomposez le problème en sous-problèmes pour développer le programme par
étapes ;
I À chaque étape, testez le code développé.
2. Tout d’abord, identifiez les types nécessaires ;
3. Identifiez les fonctions qui portent sur ces types, écrivez-les et testez-les au fur
et à mesure ;
4. Quand une fonction est difficile à écrire, créez une fonction pour chaque point
difficile.
Identifier les types

type_des_elements[][]
Type des éléments

type_des_elements ?

Nous allons utiliser int et définir les constantes :

private final static int VIDE = 0;


private final static int JAUNE = 1;
private final static int ROUGE = 2;
Types de notre programme
private final static int VIDE = 0;
private final static int JAUNE = 1;
private final static int ROUGE = 2;

...

int[][] grille;

grille[0][0] = VIDE;
grille[2][3] = JAUNE;
Premières méthodes
I initialise : méthode qui initialise une grille ;
I affiche : méthode qui affiche une grille.
Méthode initialise
private final static int VIDE = 0;
private final static int JAUNE = 1;
private final static int ROUGE = 2;

...

static void initialise(int[][] grille)


{
for(int i = 0; i < grille.length; ++i) {
for(int j = 0; j < grille[i].length; ++j) {
grille[][j] = VIDE;
}
}
}

...

int[][] grille = new int[6][7];


initialise(grille);
Méthode initialise
private final static int VIDE = 0;
private final static int JAUNE = 1;
private final static int ROUGE = 2;

...

static void initialise(int[][] grille)


{
for(int i = 0; i < grille.length; ++i) {
for(int j = 0; j < grille[i].length; ++j) {
grille[i][j] = VIDE;
}
}
}

...

int[][] grille = new int[6][7];


initialise(grille);
Méthode affiche
private final static int VIDE = 0;
private final static int JAUNE = 1;
private final static int ROUGE = 2;
...
// affiche O pour une case rouge, X pour une case jaune
static void affiche(int[][] grille)
{
for(int[] ligne : grille) {
for(int cellule : ligne) {
if (cellule == VIDE) {
System.out.print(' ');
} else if (cellule == ROUGE) {
System.out.print('O');
} else {
System.out.print('X');
}
}
System.out.println();
}
}
...
int[][] grille = new int[6][7];
initialise(grille);
Tester initialise et affiche
public static void main(String[] args)
{
int[][] grille = new int[6][7];
XO
initialise(grille);
grille[2][3] = JAUNE;
grille[2][4] = ROUGE;
affiche(grille);
}
Retour sur affiche
// affiche O pour une case rouge, X pour une case jaune
static void affiche(int[][] grille) | | | | | | | |
{ | | | | | | | |
System.out.println(); | | | |X|O| | |
for(int[] ligne : grille) { | | | | | | | |
System.out.print(" |");
for(int cellule : ligne) { | | | | | | | |
if (cellule == VIDE) { | | | | | | | |
System.out.print(' '); ==1=2=3=4=5=6=7==
} else if (cellule == ROUGE) {
System.out.print('O');
} else {
System.out.print('X');
}
System.out.print('|');
}
System.out.println();
}
System.out.print('=');
for(int i = 1; i <= grille[0].length; ++i) {
System.out.print("=" + i);
}
System.out.println("==\n");
}
Jouer...

A ce stade, nous avons vu :


I les structures de données choisies
I 2 fonctionalités simples : initialise et affiche

+ Voyons maintenant comment jouer :

I demander à un joueur où il joue


I valider son coup
I demander à l’autre joueur
c’est-à-dire alterner les joueurs
I vérifier si l’un gagne (ou si le jeu est plein)
Méthode joue
static void joue(int[][] grille, int colonne, int couleur)
{
// on parcourt la colonne en partant du bas jusqu'à trouver une case vide :
int ligne = grille.length - 1;

while (grille[ligne][colonne] != VIDE) {


--ligne;
}

// on remplit la case vide trouvée :


grille[ligne][colonne] = couleur;
}

...

joue(grille, 3, rouge);
joue(grille, 2, jaune);
joue(grille, 3, rouge);
Tester la méthode joue
static void joue(int[][] grille, int colonne, int couleur)
{
// on parcourt la colonne en partant du bas jusqu'à trouver une case vide :
int ligne = grille.length - 1;
while (grille[ligne][colonne] != VIDE) {
--ligne;
}
// on remplit la case vide trouvée :
grille[ligne][colonne] = couleur;
}
...
static void main()
{
int[][] grille = new int[6][7];
initialise(grille);
affiche(grille);
joue(grille, 3, ROUGE);
affiche(grille);
joue(grille, 2, JAUNE);
affiche(grille);
joue(grille, 3, ROUGE);
affiche(grille);
Méthode joue
static joue(int[][] grille, int colonne, int couleur)
{
// on parcourt la colonne en partant du bas jusqu'à trouver une case vide,
// ou jusqu'en haut de la colonne si la colonne est pleine :
int ligne = grille.length - 1;

boolean pleine = false;


while ((!pleine) && (grille[ligne][colonne] != VIDE)) {
if (ligne == 0) {
pleine = true;
} else {
--ligne;
}
}

// si on n'est pas arrivé jusqu'en haut de la colonne, on remplit la case vide trouvée,
// sinon c'est que la colonne est pleine et le coup n'est pas valide :
if (!pleine) {
grille[ligne][colonne] = couleur;
return true;
} else {
return false;
}
}
Méthode joue
static boolean joue(int[][] grille, int colonne, int couleur)
{
// on parcourt la colonne en partant du bas jusqu'à trouver une case vide,
// ou jusqu'en haut de la colonne si la colonne est pleine :
int ligne = grille.length - 1;

boolean pleine = false;


while ((!pleine) && (grille[ligne][colonne] != VIDE)) {
if (ligne == 0) {
pleine = true;
} else {
--ligne;
}
}

// si on n'est pas arrivé jusqu'en haut de la colonne, on remplit la case vide trouvée,
// sinon c'est que la colonne est pleine et le coup n'est pas valide :
if (!pleine) {
grille[ligne][colonne] = couleur;
return true;
} else {
return false;
}
}
Tester la nouvelle méthode joue
public static void main(String[] args)
{
int[][] grille = new int[6][7];

initialise(grille);
affiche(grille);

for(int i = 0; i < 10; ++i) {


boolean valide = joue(grille, 3, ROUGE);

if (!valide) {
System.out.println("impossible d'ajouter un pion sur cette colonne");
}

affiche(grille);
}
}
Tester la nouvelle méthode joue
static boolean joue(int[][] grille, int colonne, int couleur)
{
int ligne = grille.length - 1;
boolean pleine = false;
while ((!pleine) && (grille[ligne][colonne] != VIDE)) {
if (ligne == 0) {
pleine = true;
} else {
--ligne;
}
}
if (!pleine) {
grille[ligne][colonne] = couleur;
return true;
} else {
return false;
}
}
...
for(int i = 0; i < 10; ++i) {
boolean valide = joue(grille, 3, ROUGE);
if (!valide) {
System.out.println("impossible d'ajouter un pion sur cette colonne");
}
affiche(grille);
}
Une version alternative de la méthode joue
static boolean joue(int[][] grille, int colonne, int couleur)
{
// si la colonne est pleine, le coup n'est pas valide :
if (grille[0][colonne] != VIDE) {
return false;
}
// on parcourt la colonne en partant du bas jusqu'à trouver une case vide :
int ligne = grille.length - 1;
while (grille[ligne][colonne] != VIDE) {
--ligne;
}
// on remplit la case vide trouvée :
grille[ligne][colonne] = couleur;
return true;
}
Encore une autre version de la méthode joue
static boolean joue(int[][] grille, int colonne, int couleur)
{
int ligne = grille.length - 1;

// on parcourt la colonne en partant du bas jusqu'à trouver une case vide.


//
// Si le test (ligne >= 0) devient faux, c'est qu'on a
// soustrait 1 à ligne quand elle valait 0, ce qui arrive quand la
// colonne est pleine.
while ((ligne >= 0) && (grille[ligne][colonne] != VIDE)) {
--ligne;
}

// si ligne >= 0, on a trouvé une case vide, on la remplit,


// sinon c'est que la colonne est pleine et le coup n'est pas valide :
if (ligne >= 0) {
grille[ligne][colonne] = couleur;
return true;
} else {
return false;
}
}
Jouer...

A ce stade, nous avons vu :


I les structures de données choisies (Grille, Couleur)
I 2 fonctionalités simples : initialise et affiche
I une fonctionalité plus avancée : joue
Pour jouer, il faut :
I demander à un joueur où il joue
I valider son coup
I demander à l’autre joueur
c’est-à-dire alterner les joueurs
I vérifier si l’un gagne (ou si le jeu est plein)
Jouons !

A ce stade, nous avons vu :


I les structures de données choisies (Grille, Couleur)
I 2 fonctionalités simples : initialise et affiche
I 1 fonctionalité plus complexe : joue
qui vérifie si un coup est valide et place le jeton dans le jeu
Mais pour vraiment jouer, il nous manque :
I demander à un joueur où il joue
I la boucle principale qui alterne les joueurs
I vérifier si l’un des deux gagne (ou si le jeu est plein)
Jouons !
private static Scanner clavier = new Scanner(System.in);
public static void main(String[] args)
{
int[][] grille = new int[6][7];
initialise(grille);
affiche(grille);
int couleurJoueur = JAUNE;
do {
if (couleurJoueur == JAUNE) {
System.out.println("Joueur X : entrez un numéro de colonne");
} else {
System.out.println("Joueur O : entrez un numéro de colonne");
}
int colonne = clavier.nextInt();
}
Jouons !
public static void main(String[] args)
{
int[][] grille = new int[6][7];
initialise(grille);
affiche(grille);
int couleurJoueur = JAUNE;
do {
if (couleurJoueur == JAUNE) {
System.out.println("Joueur X : entrez un numéro de colonne");
} else {
System.out.println("Joueur O : entrez un numéro de colonne");
}
int colonne = clavier.nextInt();
// les indices des tableaux commencent par 0 en Java:
--colonne;
boolean valide = joue(grille, colonne, couleurJoueur);
if (!valide) {
System.out.println(" > Ce coup n'est pas valide");
}
affiche(grille);
}
Jouons !
do {
if (couleurJoueur == JAUNE) {
System.out.println("Joueur X : entrez un numéro de colonne");
} else {
System.out.println("Joueur O : entrez un numéro de colonne");
}
int colonne = clavier.nextInt();
// les indices des tableaux commencent par 0 en Java:
--colonne;
boolean valide = joue(grille, colonne, couleurJoueur);
if (!valide) {
System.out.println(" > Ce coup n'est pas valide");
}
affiche(grille);
// on change la couleur pour la couleur de l'autre joueur:
if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while( );
}
Jouons !
do {
demandeEtJoue(grille, couleurJoueur);
affiche(grille);
// on change la couleur pour la couleur de l'autre joueur:
if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while( );
}
Méthode demandeEtJoue
void demandeEtJoue(int[][] grille, int couleurJoueur)
{
boolean valide;

do {
System.out.print("Joueur ");
if (couleurJoueur == JAUNE) {
System.out.print("X");
} else {
System.out.print("O");
}
System.out.println(" : entrez un numéro de colonne");

int colonne = clavier.nextInt();


// les indices des tableaux commencent par 0 en Java:
--colonne;

valide = joue(grille, colonne, couleurJoueur);


if (!valide) {
System.out.println(" > Ce coup n'est pas valide");
}
} while(!valide);
}
Retour sur la méthode joue
static boolean joue(int[][] grille, int colonne, int couleur)
{
// Si le numéro de colonne n'est pas valide, le coup n'est pas valide :
if (colonne >= grille[0].length) {
return false;
}
// on parcourt la colonne en partant du bas jusqu'à trouver une case vide,
// ou jusqu'en haut de la colonne si la colonne est pleine :
int ligne = grille.length - 1;
boolean pleine = false;
while ((!pleine) && (grille[ligne][colonne] != VIDE)) {
if (ligne == 0) {
pleine = true;
} else {
--ligne;
}
}
// si on n'est pas arrivé jusqu'en haut de la colonne, on remplit la case vide trouvée,
// sinon c'est que la colonne est pleine et le coup n'est pas valide :
if (!pleine) {
grille[ligne][colonne] = couleur;
return true;
} else {
return false;
Où en sommes nous ?

A ce stade, nous avons fait :


I les structures de données choisies (Grille, Couleur)
I 2 fonctionalités simples : initialise et affiche
I 2 fonctionalité plus complexe : joue et demandeEtJoue
I la boucle principale qui alterne les joueurs
Mais pour vraiment jouer, il nous manque :
I vérifier si l’un des deux gagne (ou si le jeu est plein)
Retour sur la méthode main
int couleurJoueur = JAUNE;
boolean gagne;

do {
demandeEtJoue(grille, couleurJoueur);

affiche(grille);

gagne = estCeGagne(grille, couleurJoueur);

// on change la couleur pour la couleur de l'autre joueur:


if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while();
Retour sur la méthode main
int couleurJoueur = JAUNE;
boolean gagne;

do {
demandeEtJoue(grille, couleurJoueur);

affiche(grille);

gagne = estCeGagne(grille, couleurJoueur);

// on change la couleur pour la couleur de l'autre joueur:


if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while(!gagne);
Méthode estCeGagne : Stratégie
Méthode estCeGagne
// gagne = estCeGagne(grille, couleurJoueur);
static boolean estCeGagne(int[][] grille, int couleurJoueur)
{
for(int ligne = 0; ligne < grille.length; ++ligne) {
for(int colonne = 0; colonne < grille[ligne].length; ++colonne) {
int couleurCase = grille[ligne][colonne];
if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||
// horizontalement, vers la droite:
(compte(grille, ligne, colonne, 0, +1) >= 4) ||
// en diagonale, vers le bas et la droite:
(compte(grille, ligne, colonne, +1, +1) >= 4) ||
// verticalement, vers le bas:
(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}
return false;
}|
Méthode estCeGagne
// gagne = estCeGagne(grille, couleurJoueur);
static boolean estCeGagne(int[][] grille, int couleurJoueur)
{
for(int ligne = 0; ligne < grille.length; ++ligne) {
for(int colonne = 0; colonne < grille[ligne].length; ++colonne) {
int couleurCase = grille[ligne][colonne];
// pour chaque case qui contient un pion de la bonne couleur,
// on compte les pions de la meme couleur dans 4 directions:
if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||
// horizontalement, vers la droite:
(compte(grille, ligne, colonne, 0, +1) >= 4) ||
// en diagonale, vers le bas et la droite:
(compte(grille, ligne, colonne, +1, +1) >= 4) ||
// verticalement, vers le bas:
(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
// si le nombre de pions pour au moins une des directions
// est au moins 4, le joueur a gagne:
return true;
}
}
}
Méthode estCeGagne
// pour chaque case qui contient un pion de la bonne couleur,
// on compte les pions de la meme couleur dans 4 directions:
if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||
// horizontalement, vers la droite:
(compte(grille, ligne, colonne, 0, +1) >= 4) ||
// en diagonale, vers le bas et la droite:
(compte(grille, ligne, colonne, +1, +1) >= 4) ||
// verticalement, vers le bas:
(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
// si le nombre de pions pour au moins une des directions
// est au moins 4, le joueur a gagne:
return true;
}
}
}
}
// si on a parcouru toute la grille sans trouver au moins 4 pions
// alignes, le joueur n'a pas gagne, du moins pas encore:
return false;
}
Méthode compte
// if (compte(grille, ligne, colonne, -1, +1) >= 4 ...
static int compte(int[][] grille,
int ligneDepart, int colonneDepart,
int dirLigne, int dirColonne)
{
int compteur = 0;

int ligne = ligneDepart;


int colonne = colonneDepart;

while (grille[ligne][colonne] == grille[ligneDepart][colonneDepart] &&


ligne >= 0 && ligne < grille.length &&
colonne >= 0 && colonne < grille[ligne].length) {

++compteur;
ligne = ligne + dirLigne;
colonne = colonne + dirColonne;

return compteur;
}
Méthode compte
static int compte(int[][] grille,
int ligneDepart, int colonneDepart,
int dirLigne, int dirColonne)
{
int compteur = 0;

int ligne = ligneDepart;


int colonne = colonneDepart;

// on part de la case (ligneDepart, colonneDepart) et on parcourt la grille


// dans la direction donnee par (dirLigne, dirColonne)
// tant qu'on trouve des pions de la meme couleur que le pion de depart.
while (grille[ligne][colonne] == grille[ligneDepart][colonneDepart] &&
ligne >= 0 && ligne < grille.length &&
colonne >= 0 && colonne < grille[ligne].length) {

++compteur;
ligne = ligne + dirLigne;
colonne = colonne + dirColonne;

return compteur;
}
Retour sur la méthode estCeGagne
static boolean estCeGagne(int[][] grille, int couleurJoueur)
{
for(int ligne = 0; ligne < grille.length; ++ligne) {
for(int colonne = 0; colonne < grille[ligne].length; ++colonne) {
int couleurCase = grille[ligne][colonne];

if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
Retour sur la méthode estCeGagne
{
for(int ligne = 0; ligne < grille.length; ++ligne) {
for(int colonne = 0; colonne < grille[ligne].length; ++colonne) {
int couleurCase = grille[ligne][colonne];

if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}
Retour sur la méthode estCeGagne
for(int ligne = 0; ligne < grille.length; ++ligne) {
for(int colonne = 0; colonne < grille[ligne].length; ++colonne) {
int couleurCase = grille[ligne][colonne];

if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}
Retour sur la méthode estCeGagne
for(int colonne = 0; colonne < grille[ligne].length; ++colonne) {
int couleurCase = grille[ligne][colonne];

if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}

return false;
Retour sur la méthode estCeGagne
int couleurCase = grille[ligne][colonne];

if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}

return false;
}|
Retour sur la méthode estCeGagne
if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}

return false;
}|
Retour sur la méthode estCeGagne
if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}

return false;
}|
Retour sur la méthode estCeGagne
if (couleurCase == couleurJoueur) {
if (
// en diagonale, vers le haut et la droite:
(ligne >= 3 && colonne <= grille[ligne].length - 4 &&
compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(colonne <= grille[ligne].length - 4 &&
compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(ligne <= grille.length - 4 && colonne <= grille[ligne].length - 4 &&
compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(ligne <= grille.length - 4 &&
compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
}
}
Retour sur la méthode estCeGagne
if (couleurCase == couleurJoueur) {
final int ligneMax = grille.length - 4;
final int colonneMax = grille[ligne].length - 4;

if (
// en diagonale, vers le haut et la droite:
(ligne >= 3 && colonne <= colonneMax &&
compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(colonne <= colonneMax &&
compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(ligne <= ligneMax && colonne <= colonneMax &&
compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(ligne <= &&
compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
Retour sur la méthode estCeGagne
if (couleurCase == couleurJoueur) {
final int ligneMax = grille.length - 4;
final int colonneMax = grille[ligne].length - 4;

if (
// en diagonale, vers le haut et la droite:
(ligne >= 3 && colonne <= colonneMax &&
compte(grille, ligne, colonne, -1, +1) >= 4) ||

// horizontalement, vers la droite:


(colonne <= colonneMax &&
compte(grille, ligne, colonne, 0, +1) >= 4) ||

// en diagonale, vers le bas et la droite:


(ligne <= ligneMax && colonne <= colonneMax &&
compte(grille, ligne, colonne, +1, +1) >= 4) ||

// verticalement, vers le bas:


(ligne <= ligneMax &&
compte(grille, ligne, colonne, +1, 0) >= 4)
) {
return true;
}
}
Retour sur la méthode main
demandeEtJoue(grille, couleurJoueur);

affiche(grille);

gagne = estCeGagne(grille, couleurJoueur);

// on change la couleur pour la couleur de l'autre joueur:


if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while(!gagne);

// attention, on a change la couleur pour la couleur de l'autre joueur !


if (couleurJoueur == JAUNE) {
System.out.println("Le joueur O a gagne !");
} else {
System.out.println("Le joueur X a gagne !");
}
}
Fini ?
Retour sur la méthode main
demandeEtJoue(grille, couleurJoueur);

affiche(grille);

gagne = estCeGagne(grille, couleurJoueur);

// on change la couleur pour la couleur de l'autre joueur:


if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while(!gagne && !plein(grille));

// attention, on a change la couleur pour la couleur de l'autre joueur !


if (couleurJoueur == JAUNE) {
System.out.println("Le joueur O a gagne !");
} else {
System.out.println("Le joueur X a gagne !");
}
}
Retour sur la méthode main
// on change la couleur pour la couleur de l'autre joueur:
if (couleurJoueur == JAUNE) {
couleurJoueur = ROUGE;
} else {
couleurJoueur = JAUNE;
}
} while(!gagne && !plein(grille));

if (gagne) {
// attention, on a change la couleur pour la couleur de l'autre joueur !
if (couleurJoueur == JAUNE) {
System.out.println("Le joueur O a gagne !");
} else {
System.out.println("Le joueur X a gagne !");
}
} else {
System.out.println("Match nul !");
}
}
Fonction plein
Méthode plein
// plein(grille)
static boolean plein(int[][] grille)
{
// Si on trouve une case vide sur la premiere ligne, la grille n'est pas pleine :
for(int cellule : grille[0]) {
if (cellule == VIDE) {
return false;
}
}

// Sinon, la grille est pleine :


return true;
}|
Évaluation paresseuse
J. Sam, J.-C. Chappelier, V. Lepetit

version 1.0 de septembre 2013

L’évaluation d’une expression conditionnelle telle que :

(i != 0) && (25 / i > 12)

pose-t-elle problème à l’exécution si la variable i vaut 0 ?

On peut en effet se poser la question puisque si i vaut 0, le second opérande (25 / i > 12)
de l’expression conditionnelle va causer une division par zéro s’il est évalué.

La réponse à cette question est en fait NON en raison de ce que l’on appelle l’évaluation
paresseuse ("lazy evaluation" en anglais) : l’évaluation des opérandes se fait de la gauche
vers la droite et seuls les opérandes nécessaires à la détermination de la valeur logique sont
évalués. Dans le cas de notre exemple, comme l’opérande (i != 0) est faux, l’expression
conditionnelle est fausse et (25 / i > 12) n’est pas évaluée.

De façon générale :
– pour une condition de la forme X1 && X2 && ... && Xn, les opérandes Xi ne
sont évalués que jusqu’au premier opérande faux (s’il existe, auquel cas la condition est
fausse, sinon elle est vraie) ;
– pour une condition de la forme X1 || X2 || ... || Xn, les opérandes ne sont évalués
que jusqu’au premier opérande vrai (s’il existe, auquel cas la condition est vraie, sinon
elle est fausse).

L’évaluation des conditions suivantes ne causera donc aucun problème à l’exécution même
si i vaut 0 :
– (i != 0) && (25 / i > 12)
– (i == 0) || (25 / i < 12)

1
L’instruction conditionnelle switch
J. Sam, J.-C. Chappelier, V. Lepetit

version 1.0 de octobre 2013

En Java, on peut écrire de façon plus synthétique l’enchaînement de plusieurs conditions


dans le cas où l’on teste différentes valeurs d’une expression retournant un entier (ou une
chaîne de caractère depuis Java 7).

1 L’instruction switch
Ainsi une séquence d’instructions if telle que celle-ci :

if (i == 1)
Instructions 1
else if (i == 12)
Instructions 2
...
else if (i == 36)
Instructions N
else
Instructions N+1

peut avantageusement être remplacée par la tournure suivante :

switch (i) {
case 1:
Instructions 1;
break;
case 12:
Instructions 2;
break;
...
case 36:
Instructions N;
break;
default:
Instructions N+1;
break;
}

1
Lors de l’exécution d’un instruction switch, l’expression suivant le mot clé switch est
évaluée 1 . L’exécution se poursuit alors au niveau du case correspondant au résultat de
l’évaluation.
Cette exécution continue en séquence, sans aucune évaluation de condition, jusqu’à ce que
le mot réservé break soit rencontré ou que la fin de l’instruction soit atteinte.
La première portion de code ci-dessus n’est donc équivalente, du point de vue de l’exé-
cution, qu’à un switch où chaque cas de termine par un break (comme c’est le cas de
l’exemple ci-dessus).
Dans le cas où l’évaluation de l’expression ne retourne pas une valeur correspondant à un
case, le programme exécute les instructions correspondant au cas par défaut (précédées
du mot clé default).

2 Rôle du break : exemple


Examinons l’exemple suivant :

switch (a+b) {
case 2:
case 8: instruction2; // lorsque (a+b) vaut 2 ou 8
case 4:
case 3: instruction3; // lorsque (a+b) vaut 2, 3, 4 ou 8
break;
case 0: instruction1; // exécuté uniquement lorsque
break; // (a+b) vaut 0
default: instruction4; // dans tous les autres cas
break;
}

Supposons que l’évaluation de l’expression (a + b) retourne 8. L’exécution va se dérouler


comme suit :
1. le programme va se « brancher » au cas 8 et ainsi exécuter l’instruction instruction2 ;
2. comme il n’y a pas d’instruction break en dessous, l’exécution se poursuit et tra-
verse le cas 4 (sans faire de test et sans rien faire puisqu’il n’y a pas d’instructions à
exécuter) ;
3. c’est ensuite instruction3 qui est rencontrée et exécutée ;
4. on rencontre finalement le break en dessous de instruction3 et l’on peut ainsi
sortir de l’instruction switch.
On voit donc ainsi que
– on exécutera l’instruction instruction2 si (a + b) vaut 2 ou 8 ;
– on exécutera l’instruction instruction3 si (a + b) vaut 2, 3, 4 ou 8 ;
– on n’exécutera instruction1 que si (a + b) vaut 0.
1. dans l’exemple qui précède, l’expression se réduit à la simple variable i

2
Le fait de ne pas mettre d’instruction en face d’un cas permet simplement de mettre en
œuvre un « ou logique » entre plusieurs conditions : on exécute instruction2 si (a +
b) vaut 2 ou 8 par exemple. Cela permet d’éviter des répétitions inutiles de code. Mais il
vaut peut être mieux dans un premier temps éviter ce genre d’optimisation, peu facilement
compréhensible à la première lecture...

3 switch vs if..else
switch est moins général que if..else :
– la valeur sur laquelle on teste doit être soit de type intégral : char, int, byte, short
. . . ou String (mais ce dernier type seulement depuis Java 7) ;
– l’expression testée est toujours la même (le « i » ou « a+b » des exemples précédents) ;
– les cas doivent être des constantes (pas de variables).

3
i++ ou ++i ?
J.-C. Chappelier, J. Sam, V. Lepetit

version 1.0 de septembre 2013

On rencontre souvent dans la littérature et dans des exemples de code l’utilisation de l’opé-
rateur d’incrémentation postfixé, comme par exemple dans l’expression i++, alors que
dans le cours nous avons opté pour une notation préfixée, par exemple ++i.
Y a-t-il une différence et si oui quelle est-elle ? Et pourquoi un tel choix pour le cours ?

1 Effet et valeur
Avant tout vous ne pourrez pas pleinement comprendre ce dont il s’agit si vous ne distin-
guez pas ce que fait une expression de ce qu’elle vaut.
En Java, toute expression fait quelque chose et vaut quelque chose. Elle vaut quelque chose
en ce sens qu’on peut par exemple la mettre à droite d’une affectation.
Par exemple, « i = 3 » est une affectation, mais en Java, c’est aussi une expression. C’est
une expression qui fait une affectation de la valeur 3 à la variable i. Mais cette expression
vaut aussi quelque chose, c’est-à-dire que l’on peut parfaitement écrire : j = i = 3; ce
qui signifie : j = (i = 3); ou encore : « met dans j la valeur de l’expression ‘i =
3’ ». Ceci est tout à fait licite en Java.
Je m’empresse immédiatement de dire qu’il faut absolument éviter d’utiliser ce genre d’ex-
pressions qui rendent le code beaucoup moins intelligible. Rappelez vous que vous devez
toujours écrire le code le plus clair possible !
Que vaut donc l’expression « i = 3 » ? Il se trouve qu’elle vaut le résultat de l’affectation,
donc 3 ici. Ainsi j = (i = 3); est la même chose que
i = 3;
j = i;

2 i++ et ++i
Je peux maintenant expliquer la différence entre les expressions « i++ » et « ++i »:
– ces deux expressions font exactement la même chose : elles incrémentent i ;
– en revanche, leurs valeurs sont différentes.

1
Si vous n’utilisez pas la valeur de ces expressions 1 , il n’y aura donc pour vous aucune
différence.
Utiliser leur valeur signifierait par exemple écrire des choses comme : j = ++i;, ce que
je vous déconseille une fois de plus de faire.
Leur seule différence est donc au niveau de leur valeur : i++ vaut la valeur de i avant
incrémentation alors que ++i vaut la valeur de i après incrémentation.
Si l’on prend l’exemple suivant :
int i = 3;
int j = i; // i et j ont la même valeur
int k = 0;
int l = 0;
k = ++i; // opérateur préfixé
l = j++; // opérateur postfixé

A l’issue de ce bout de code, i et j auront tous les deux la valeur 4 (les deux opérateurs font
la même chose), mais k aura la valeur 4 alors que l aura la valeur 3 (les deux opérateurs
ne valent pas la même chose).

3 Lequel préférer ?
Encore une fois, si vous n’utilisez pas la valeur de retour et si vous n’êtes pas dans un
langage qui permette de surcharger (= redéfinir) ces opérateurs 2 , alors il n’y aura pour
vous aucune différence pratique entre ces deux notations.
Ceci dit, il y deux bonnes raisons de préférer la notation préfixée (++i) à celle postfixée
(i++) : l’une conceptuelle et l’autre plus pragmatique dans les langages où ces opérateurs
peuvent être surchargés.
La raison conceptuelle est la suivante : quelle opération voulons nous exprimer par i++
(ou ++i) ? Si c’est « i = i + 1 » alors la seule qui lui soit totalement équivalent est
++i.
En effet, quelle est la valeur de l’expression i = i + 1 ? C’est bien la valeur de i après
incrément, la même que celle de ++i.
En d’autres termes, par quoi remplacer i = i + 1 dans
j = i = i + 1;
Le seul remplacement valide entre i++ et ++i est le second :
j = ++i;

Voilà pour la raison conceptuelle.


1. Et si vous ne surchargez pas ces opérateurs, voir la section «Lequel préférer ?».
2. Java ne le permet pas, mais C++ oui.

2
D’un point de vue pratique maintenant : si le langage permet de surcharger ces opérateurs
(C++, qui est l’objet de notre autre cours, le permet), alors il faut toujours préférer la
notation préfixée (++i) car elle est sensiblement moins coûteuse.
Je prétends en effet, sans le démontrer ici, que l’opérateur préfixé peut s’implémenter sans
aucune copie, alors qu’il est impossible de faire l’opérateur postfixé sans copie. L’opérateur
postfixé coûte donc toujours une copie de plus que l’opérateur préfixé. Si ces opérateurs
sont surchargés pour des objets coûteux à copier, alors la différence de performance se fera
sentir !
Pour ces deux raisons, il est donc préférable d’utiliser l’opérateur préfixé (++i) à celui
postfixé (i++). Et c’est pour cela qu’il en est ainsi dans ce cours.

3
Limitations des types entiers et réels
V. Lepetit, J. Sam, et J.-C. Chappelier

1 Limitations des types entiers


Le type int n’est pas le seul type qu’on peut utiliser pour déclarer des variables contenant
des valeurs positives. Il existe aussi les types : long et short. Par exemple, on peut
écrire :
int m;
long n;
short p;

Cependant, tous ces types ne peuvent représenter que des valeurs comprises dans un certain
intervalle. Pour donner une idée de l’ordre de grandeur, voici les intervalles utilisés par
Java :

type valeur minimale valeur maximale


short -32’678 +32’767
int -2’147’483’648 -2’147’483’647
long environ −1018 +1018

Plus l’intervalle est grand, plus une variable du type correspondant occupera de place en
mémoire.

Pour voir l’impact que peuvent avoir ces limitations en pratique, vous pouvez exécuter le
programme suivant 1 :
public class Depassement {

public static void main(String[] args) {

int n = 10;

System.out.println( n );
n = n * n;
System.out.println( n );
1. Ce programme pourra se réécrire de façon plus compacte dès que vous aurez vu les boucles.

1
n = n * n;
System.out.println( n );
n = n * n;
System.out.println( n );
n = n * n;
System.out.println( n );
n = n * n;
System.out.println( n );

Ce programme initialise la variable n à 10, et l’élève au carré plusieurs fois. Les valeurs
affichées devraient donc être toutes des puissances de 10, mais en exécutant le programme,
vous verrez que ce n’est pas le cas pour les dernières valeurs, qui sont trop grandes pour
être représentées correctement par le type int. Vous pouvez également changer le type de
n de int à long et short pour voir l’impact sur les valeurs calculées.
Soyez donc vigilants quand votre programme doit travailler avec de grandes valeurs !

2 Limitations des types réels


De la même façon, le type double ne peut pas représenter n’importe quel nombre réel,
puisqu’il faudrait pour cela une précision infinie. Il existe également le type float qui
est plus limité que le type double, mais prend moins de place en mémoire. Voici les
intervalles de valeurs pour ces types :

type valeur minimale valeur maximale


float −3.4 1038 +3.4 1038
double −1.8 10308 +1.8 10308

Mais en pratique, la limitation de ces types affecte surtout la précision des valeurs représen-
tées : les valeurs réelles, y compris celles entre les intervalles donnés ci-dessus, ne peuvent
pas toutes être représentées. Considérons le programme suivant :

public class Imprecision {

public static void main(String[] args) {

double a = 37.0;
double racine = Math.sqrt(a);

System.out.println( a - racine * racine );

2
}
}

Si le type double pouvait représenter parfaitement les valeurs réelles, ce programme


afficherait 0. Or, sur mon ordinateur, j’obtiens environ la valeur 7 10−15 , qui est une valeur
très petite mais pas nulle. C’est parce que la variable racine ne peut stocker exactement
la racine de a, et donc l’expression racine * racine ne vaut pas exactement a.
C’est pour ça que les tests d’égalité ou d’inégalité entre double (ou float) NE DE-
VRAIENT PAS ÊTRE utilisés 2 . Par exemple, le code suivant :

double a = 37.0;
double racine = Math.sqrt(a);

if (a == racine * racine) {
System.out.println( "ok" );
}

n’affiche rien, contrairement à ce qu’on pourrait s’attendre. Si vous devez absolument com-
parer des valeurs de type double vous pouvez utiliser un test tel que celui-ci :

double a = 37.0;
double racine = Math.sqrt(a);

if (abs(a - racine * racine) < epsilon) {


System.out.println( "ok" );
}

où epsilon est une très petite valeur et abs calcule la valeur absolue. Cette valeur de-
vrait être choisie selon la précision du type utilisé, mais comment déterminer cette valeur
idéalement sort largement du cadre de ce cours.

2. Nous utilisons parfois de tels tests dans notre cours, mais uniquement par souci de simplicité.

Vous aimerez peut-être aussi