Vous êtes sur la page 1sur 91

REPUBLIQUE TUNISIENNE

MINISTERE DE L’ENSEIGNEMENT SUPERIEUR ET DE


LA RECHERCHE SCIENTIFIQUES ET TECHNOLOGIQUES

Institut Supérieur des Etudes ‫المعهد العالي للدراسات التكنولوجية‬


Technologiques de Kasserine
‫بالقصرين‬

Département Technologies de
l’Informatique

SUPPORT DE COURS
Avec exercices corrigés

Programmation Objet Avancée

Réalisé par :
Mme Leila NAKKAII Technologue à l’ISET DE KASSERINE

Année Universitaire : 2019/2020

1
Table des matières
Table des matières ........................................................................................................................................2
Chapitre 1 La généricité en Java ....................................................................................................................6
1. Principe de base ....................................................................................................................................6
2. Classes génériques ................................................................................................................................8
3. Methodes génériques ...........................................................................................................................9
4. Généricité et Héritage ........................................................................................................................ 10
Chapitre 2 Les collections ........................................................................................................................... 11
1. L'API Collections ................................................................................................................................. 12
2. Les interfaces des collections ............................................................................................................. 13
2.1. Constructeurs ............................................................................................................................. 13
2.2. Méthodes ................................................................................................................................... 13
3. L'interface Iterator ............................................................................................................................. 14
4. L'interface List .................................................................................................................................... 14
5. La classe ArrayList............................................................................................................................... 16
6. L'interface Set ..................................................................................................................................... 20
7. La classe HachSet............................................................................................................................... 21
Chapitre 3 Gestion des entrées/sorties(Les flots de base en java) ............................................................ 23
1. Les fondements de la notion de flot .................................................................................................. 24
2. Les flots d’entrée/sortie ..................................................................................................................... 26
2.1. InputStream et OutputStream ................................................................................................... 26
2.2. DataInputStream et DataOutputStream .................................................................................... 28
3. Les flots de caractères : Readers et Writers ....................................................................................... 28
3.1. Le format Unicode ...................................................................................................................... 28
3.2. Octet <-> Conversion de caractères ........................................................................................... 28
3.3. BufferedReader et BufferedWriter ............................................................................................ 29
Chapitre 4 Gestion des entrées/sorties (Les classes Path et File en java) ................................................. 29
1. Utilisation des classes path ................................................................................................................ 30
1.1. Créer un chemin ......................................................................................................................... 30
1.2. Récupérer des informations sur un chemin ............................................................................... 31

2
1.3. Vérification de l'accessibilité des fichiers ................................................................................... 32
1.4. Suppression d'un chemin ........................................................................................................... 33
1.5. Attributs de fichier ..................................................................................................................... 34
2. Lecture et écriture dans un fichier en java......................................................................................... 35
2.1. Ecrire dans un fichier .................................................................................................................. 36
2.2. Lecture d'un fichier..................................................................................................................... 37
3. Fichiers à accès aléatoire en java ....................................................................................................... 38
Chapitre 5 Les threads ............................................................................................................................... 40
1. Définition des caractéristiques d'un thread ....................................................................................... 41
1.1. Attributs de la classe Thread java............................................................................................... 41
1.2. Méthodes utiles de la classe Thread Java ................................................................................. 42
2. Eligibilité d’un thread ......................................................................................................................... 43
3. Création et exécusion d’un Thread .................................................................................................... 44
1.3. Création de threads en héritant de la classe Thread ................................................................. 44
1.4. Création de threads en implémentant l'interface Runnable ..................................................... 45
4. Synchronisation des threads en java .................................................................................................. 46
1.5. Principe de la synchronisation ................................................................................................... 46
1.6. Avantages de la Synchronisation................................................................................................ 49
1.7. Limites de la Synchronisation ..................................................................................................... 49
Chapitre 6 Construction d’une interface graphique en java ...................................................................... 50
1. Interface Graphique ........................................................................................................................... 51
1.1. Les APIs Graphiques ................................................................................................................... 51
1.2. Application graphique ................................................................................................................ 51
1.3. Hiérarchie des classes de AWT ................................................................................................... 51
2. Les Composants .................................................................................................................................. 52
3. Les Conteneurs ................................................................................................................................... 57
4. Les gestionnaires de présentation ..................................................................................................... 58
Chapitre 7Gestion des évènements ........................................................................................................... 61
1. L'interception des actions de l'utilisateur .......................................................................................... 62
2. Implémenter les méthodes déclarées dans les interfaces ................................................................. 63
2.1. L'interface ItemListener ............................................................................................................. 64
2.2. L'interface TextListener .............................................................................................................. 66
2.3. L'interface MouseMotionListener .............................................................................................. 66
2.5. L'interface WindowListener ....................................................................................................... 68

3
3. Les différentes implémentations des Listeners.................................................................................. 69
3.1. Classe implémentant elle même le listener ............................................................................... 69
3.2. Une classe indépendante implémentant le listener .................................................................. 70
3.3. Une classe interne ...................................................................................................................... 71
3.4. Une classe interne anonyme ...................................................................................................... 72
Chapitre 8 JDBC (Java DataBase Connectivity) .......................................................................................... 73
1. Les outils nécessaires pour utiliser JDBC ............................................................................................ 73
1.1. Les types de pilotes JDBC ........................................................................................................... 73
1.2. Le choix du pilote JDBC à utiliser ................................................................................................ 74
1.3. La présentation des classes de l'API JDBC .................................................................................. 74
2. La connexion à une base de données ................................................................................................ 75
2.1. Le chargement du pilote ............................................................................................................ 75
2.2. L'établissement de la connexion ................................................................................................ 76
3. L'accès à la base de données .............................................................................................................. 77
3.1. L'exécution de requêtes SQL ...................................................................................................... 77
3.2. La classe ResultSet...................................................................................................................... 78
3.3. Un exemple complet de mise à jour et de sélection sur une table ............................................ 80
4. L'utilisation d'un objet de type PreparedStatement .......................................................................... 82
5. Le traitement des erreurs JDBC .......................................................................................................... 84
Chapitre 9 JavaFX ...................................................................................................................................... 85
1. Architecture technique et module de JavaFX .................................................................................... 86
1.1. Architecture technique .............................................................................................................. 86
1.2. Module de JavaFX....................................................................................................................... 87
2. Les caractéristiques Java FX ............................................................................................................... 87
3. Comment se présente une application JavaFX ? ................................................................................ 87
4. Cycle de vie d'une application JavaFX ................................................................................................ 89
5. Traiter une action de l'utilisateur ....................................................................................................... 90
Bibliographie .............................................................................................................................................. 91

4
OBJECTIFS

Objectifs généraux
Acquérir les connaissances nécessaires pour développer une application JAVA en
utilisant des concepts avancés, basés sur les notions acquises dans le module POO.

Objectifs spécifiques
Comprendre et implémenter des classes paramétrables
Connaitre et utiliser les collections pour gérer les données applicatives
Comprendre l’échange des données entre le programme et des sources de données
externes
Maitriser les étapes de connexion et de manipulation des données d’une BD
Répartir différents traitements d'un même programme en plusieurs unités distinctes
pour permettre leur exécution simultanée

5
Chapitre 1 La généricité en Java

Objectifs

 Présenter le principe de base de la généricité,


 Comprendre et manipuler les classes génériques,
 Comprendre et manipuler les méthodes génériques,
 Connaitre et comprendre l’utilisation de la généricité avec l’héritage.

La généricité est un concept, ajouté au JDK depuis la version 1.5. Ce chapitre présente le principe de la
généricité, les classes génériques, les méthodes génériques et l’héritage des classes génériques.

1. Principe de base
Activité de démarrage :
1-Donner le code d’une classe nommé MyClass perenant :

6
 un attribut Val de type String
 Un constructeur parametré
 Un accesseur

Solution
public class MyClass
{String val ;
public MyClass (String valeur){val=valeur ;}
public String GetVal(){return val;}
}

2-Modifier cette classe pour quelle puisse manipuler une valeur de n’importe quelle
type.

Solution
public class MyClass
{Object val ;
public MyClass(Object valeur){val=valeur ;}
public Object GetVal(){return val;}}

3- Après ecriture du code ci-dessous, nous n’obtenons pas des erreurs de compilation, mais à
l’exécution, l’erreur: CastException est leveé. Déduire les limites de l’utilisation de type
Object ?
public class Test {
public static void main(String[] args) {
MyClass s=new MyClass(12);
Double x= (double) s.getValeur() ;//Le casting est obligatoire }}

Solution
 Le casting est obligatoire avec le type Object
 Les erreurs CastException ne sont pas levées lors de la compilation
 Les erreurs CastException sont levées lors de l’exécution

Pour palier à ce probléme, nous allons paramétrer la classe MyClass et ses méthodes par un type
symbolisé par <T> qui sera définit lors de l’instantiation de la classe .C’est la notion de la généricité

Définition

La généricité permet de spécifier des types génériques pour les variables incluant :
types génériques pour une classe, type de retour des méthodes et les paramètres des
méthodes et des constructeurs. [1]

7
2. Classes génériques
Syntaxe
Pour définir un type générique pour une classe il faut suivre son nom par un identifiant qui
doit être placé entre les caractères « < » et « > »[2].
Exemple
public class ClasseGen <T > // ici ClassGen est une une classe générique prenant un seul
// paramétre générique T .

Note :
 Il est possible de spécifier plusieurs types génériques ; les noms des types génériques doivent
être placés l'un à coté de l'autre séparés par le caractère «, » : <T ,R, E>.
 Le type générique peut être utilisé comme :
o Type des attributs et des variables
o Type de retour des méthodes
o Type des paramètres des méthodes et
o Type des paramètres des constructeurs [1].
Activité 2
1- Modifier la classe MyClass en utilisant la généricité.
Solution
public class MyClass <T> {
private T val;
public MyClass(T valeur){ val= valeur; }
public T getValeur(){return val ;} }
Remarque : Dans cette classe, le T n'est pas encore défini. Par contre, une fois instancié avec un type,
l'objet ne pourra travailler qu'avec le type de données que vous lui avez spécifié.

2- Instantier la classe MyClass avec T est un Integer, puis T est un String


Solution
public static void main(String[] args) {
MyClass<Integer> s1 = new MyClass<Integer> (12);
int nbre = s1.getValeur();
MyClass<String> s2=new MyClass <String>("toto ") ;
String chaine= s2.getValeur(); }
Exercice d’application 1 :
Donner le code d’une classe générique Duo ayant :
 Deux paramétre générique valeur1 de type T et valeur2 de type S
 Définir deux constructeurs pour cette classe (pramétré et sans paramétres)
 Definir les accesseurs et les mutateurs .

Solution
public class Duo<T, S> { this.valeur2 = val2;}
//Variable d'instance de type //Méthodes d'initialisation des deux valeurs
T public void setValeur(T val1, S val2){

8
private T valeur1; //Variable this.valeur1 = val1;
d'instance de type S this.valeur2 = val2;}
private S valeur2; //Retourne la valeur T
//Constructeur par défaut public T getValeur1() {
public Duo(){ return valeur1;}
this.valeur1 = null; //Définit la valeur T
this.valeur2 = null;} public void setValeur1(T valeur1) {
//Constructeur avec this.valeur1 = valeur1;}
paramètres //Retourne la valeur S
public Duo(T val1, S val2){ public S getValeur2() {
this.valeur1 = val1; return valeur2; }
//Définit la valeur S
public void setValeur2(S valeur2) {
this.valeur2 = valeur2; }}

Exercice d’application 2 :
Donner le résultat d’exécution du code suivant
public static void main(String[] args) {
Duo<String, Boolean> dual = new Duo<String, Boolean>("toto", true);
System.out.println("Valeur de l'objet dual : val1 = " + dual.getValeur1() + ", val2 = " +
dual.getValeur2());
Duo<Double, Character> dual2 = new Duo<Double, Character>(12.2585, 'C');
System.out.println ("Valeur de l'objet dual2 : val1 = " + dual2.getValeur1() + ", val2 = " +
dual2.getValeur2()); }
Solution
Le résultat de l’exécution est le suivant :
Valeur de l’objet dual : val1=toto, val2=true
Valeur de l’objet dual2 : val1=12.25895, val=c

3. Methodes génériques
Une méthode générique est une méthode paramétrée par un ensemble de types <T1,T2…>. Une
méthode générique peut être incluse ou non dans une classe générique. [2]

Syntaxe
…… <T1,T2…> Type-Retour Nom-methode (……….){…….} ;

Exemple
public <T> void affiche (T[]tabs,int n)
{for (int i=0 ; i<n ; i++) System.out.println(tabs[i]) ;}
//Cette méthode permet d’afficher un tableau dont les éléments sont de n’importe quel
type.
Exercice d’application 3 :

9
1- Ecrire le code d’une méthode générique statique qui permet de permuter deux
éléments d’ordre i et j dans un tableau de type T
2- Tester la méthode permute avec tas= {"java","pyton","c#"}; puis avec
tabf={4.14f,3.12f};

Solution
public class MyClass{
public static <T> void permute(T[] tab, int i, int j){
T temp = tab[i];
tab[i] = tab[j];
tab[j] = temp;}}
public class TestMyClass {
public static void main(String[] args) {
String[] tabs = new String[]{"java","pyton","c#"};
Float[] tabf = new Float[]{4.14f,3.12f};
MyClass.<String>permute(tabs,1,2);
MyClass.<Float>permute(tabf,0,1);
}}

4. Généricité et Héritage

Une classe générique, peut être étendue par une autre classe mais à condition que les variables types de la
classe fille soient les même que la classe mére.

Syntaxe
public class B <T1,T2,..> exetends A <T1,T2,..>{………………..}
 Ici la classe fille B hérite de la classe mére A. Les classes Aet B ont les mêmes
variables types
 La relation d'héritage est valide entre instances de A et B par un même type de
variables.

Exemple
 B <String> est sous-classe de A <String>
 B <Float> est une sous-classe de A <Float>

Note :
La relation d'héritage est invalide pour des instances de A et B qui ont des types différents, même si ces
types sont liés par héritage.

Exemple
Integer est un sous type de Object mais B<Integer> n’est pas une sous classe de
A<Object>.

10
Chapitre 2 Les collections

Objectifs

 Présenter les caractéristiques et les avantages d’utilisation de l’API


Collections,
 Connaitre et comprendre l’utilisation de l’interface Iterator,
 Connaitre et comprendre l’utilisation de l’interface Comparator,
 Connaitre et comprendre l’utilisation des interfaces List et Set,
 Définir les méthodes de base de parcours, d’utilisation et de manipulation des
classes ArrayList et HashSet.

Un programme orientée objet est censé de manipuler ses données qui peuvent etre un ensemble
d’objets mais jusqu’à maintenant on connait juste l’utilisation des tableaux.En effet les tableaux ne
peuvent pas répondre à tous les besoins de stockage d'un ensemble d'objets et surtout ils manquent de
fonctionnalités. Une solution adéquate a lieu avec les collections : une large diversité
d'implémentations proposées par l'API Collections de Java permet de répondre à la plupart des
besoins de stockage[3].

11
1. L'API Collections

Les collections sont des objets qui permettent de gérer et de stocker de multiples objets qui peuvent
être définis avec plusieurs caractéristiques tels que la possibilité de gérer des doublons, de gérer un
ordre de tri, etc. ...

Définition

Une collection est un regroupement d'objets qui sont désignés sous le nom
d'éléments.

L'API Collections propose quatre grandes familles de collections, chacune définie par une interface:

 Set : interface pour des objets qui n'autorisent pas de doublons dans l'ensemble
 List : interface pour des objets qui autorisent des doublons et un accès direct à un élément
 Map : interface qui définit des méthodes pour des objets qui gèrent des collections sous la
forme clé/valeur
 Queue et Deque : collections qui stockent des éléments dans un certain ordre avant qu'ils ne
soient extraits pour traitement

De plus ce framework propose plusieurs classes qui implémentent ces interfaces et qui peuvent être
directement utilisés [3]:

 ArrayList : tableau dynamique qui implémente l'interface List


 LinkedList : liste doublement chaînée (parcours de la liste dans les deux sens) qui implémente
l'interface List
 HashSet : Hashtable qui implémente l'interface Set
 TreeSet : arbre qui implémente l'interface SortedSet
 HashMap : Hashtable qui implémente l'interface Map
 TreeMap : arbre qui implémente l'interface SortedMap

Note1 : Pour faciliter le parcours des collections, l’API Collection propose les deux interfaces
suivantes :

 Iterator : interface pour le parcours des collections,


 ListIterator : interface pour le parcours des listes dans les deux sens et pour modifier les
éléments lors de ce parcours.

Note2 : Pour faciliter le tri des collections, l’API Collection propose les deux interfaces suivantes :

 Comparable : interface pour définir un ordre de tri naturel pour un objet,


 Comparator : interface pour définir un ordre de tri quelconque.

12
2. Les interfaces des collections
2.1. Constructeurs

Chaque implémentation de l'interface Collection devrait fournir au moins deux constructeurs[3] :

 Un constructeur par défaut (sans argument)


 Un constructeur qui attend en paramètre un objet de type collection qui va créer une collection
contenant les éléments de la collection fournie en paramètre. [3]

2.2.Méthodes

Plusieurs méthodes ont été définit par l'interface Collection :

Méthode Rôle
boolean add(E e) Ajouter un élément à la collection (optionnelle)
boolean addAll(Collection<? Ajouter tous les éléments de la collection fournie en
extends E> c) paramètre dans la collection (optionnelle)
void clear() Supprimer tous les éléments de la collection
boolean contains(Object o) Retourner un booléen qui précise si l'élément est
présent dans la collection
boolean containsAll Retourner un booléen qui précise si tous les éléments
(Collection<?> c) fournis en paramètres sont présents.
boolean equals(Object o) Vérifier l'égalité avec la collection fournie en paramètre
boolean isEmpty() Retourner un booléen qui précise si la collection est
vide
Iterator<E> iterator() Retourner un Iterator qui permet le parcours des
éléments de la collection
boolean remove(Object o) Supprimer un élément de la collection s'il est présent
(optionnelle)
boolean Supprimer tous les éléments fournis en paramètres de la
removeAll(Collection<?> c) collection s'ils sont présents (optionnelle)
boolean Ne laisser dans la collection que les éléments fournis en
retainAll(Collection<?> c) paramètres
int size() Retourner le nombre d'éléments contenus dans la
collection
Object[] toArray() Retourner un tableau contenant tous les éléments de la
collection
<T> T[] toArray(T[] a) Retourner un tableau typé de tous les éléments de la
collection

Note :

 Il ne faut pas ajouter dans une collection une référence à la collection elle-même.

13
 Certaines méthodes de cette interface peuvent lever une exception de type
UnsupportedOperationException car leur implémentation est optionnelle : add(), addAll(),
remove(), removeAll, retainAll() et clear(). Cette exception peut aussi être levée si l'opération
n'a aucune influence sur l'état de la collection[13][14]..

3. L'interface Iterator

Cette interface définit des méthodes pour des objets capables de parcourir les données d'une
collection.

Méthode Rôle

boolean hasNext() Indiquer s'il reste au moins un élément à parcourir dans la collection
Object next() Renvoyer le prochain élément dans la collection
void remove() Supprimer le dernier élément parcouru

Note :

 La méthode next() lève une exception de type NoSuchElementException si elle est appelée
alors que la fin du parcours des éléments est atteinte. Pour éviter la levée de cette exception,
il suffit d'appeler la méthode hasNext() et selon le résultat de conditionner l'appel à la
méthode next().
 La méthode remove() permet de supprimer l'élément renvoyé par le dernier appel à la
méthode next(). Il est ainsi impossible d'appeler la méthode remove() sans un appel
correspondant à next() : on ne peut pas appeler deux fois de suite la méthode remove().

Exemple 1 : parcours avec Iterator


Iterator iterator = collection.iterator();
while (iterator.hasNext())
{ System.out.println("objet = "+iterator.next());}
Exemple 2 : suppression du premier élément
Iterator iterator = collection.iterator();
if (iterator.hasNext())
{ iterator.next();
itérator.remove(); }

Remarque : Si aucun appel à la méthode next() ne correspond à celui de la méthode remove(), une
exception de type IllegalStateException est levée.

4. L'interface List

Cette interface, ajoutée à Java 1.2, étend l'interface Collection. Une collection de type List permet :

14
 de contenir des doublons
 d'interagir avec un élément de la collection en utilisant sa position
 d'insérer des éléments null

Pour les listes, une interface particulière est définie pour permettre le parcours dans les deux sens de
la liste et réaliser des mises à jour : l'interface ListIterator

L'interface List définit plusieurs méthodes qui permettent un accès aux éléments de la liste à partir
d'un index, de gérer les éléments, de rechercher la position d'un élément, d'obtenir une liste partielle
(sublist) et d'obtenir des Iterator [14] :

Méthode Rôle
void add(int index, E e) Ajouter un élément à la position fournie en paramètre
boolean addAll(int index, Ajouter des éléments à la position fournie en paramètre
Collection<? extends E> c)
E get(int index) Retourner l'élément à la position fournie en paramètre
int indexOf(Object o) Retourner la première position dans la liste du premier
élément fourni en paramètre. Elle renvoie -1 si l'élément
n'est pas trouvé
int lastIndexOf(Object o) Retourner la dernière position dans la liste du premier
élément fourni en paramètre. Elle renvoie -1 si l'élément
n'est pas trouvé
ListIterator<E> listIterator() Renvoyer un Iterator positionné sur le premier élément de
la liste
ListIterator<E> listIterator(int Renvoyer un Iterator positionné sur l'élément dont l'index
indx) est fourni en paramètre
E remove(int index) Supprimer l'élément à la position fournie en paramètre
E set(int index, E e) Remplacer l'élément à la position fournie en paramètre
List<E>subList(int fromIndex Obtenir une liste partielle de la collection contenant les
, int toIndex) éléments compris entre les index fromIndex inclus et
toIndex exclus fournis en paramètres

Note :

 La collection de type List obtenue en invoquant la méthode subList() est liée à la collection
qui a permis sa création.
 Une modification faite dans la sous liste est reportée dans la liste originelle.
 Si un élément est ajouté ou supprimé dans la liste originelle alors une exception de type
ConcurrentModificationException est levée lors d'une utilisation de la sous liste

Exercice d’application 1 :
Essayer de comprendre le code suivant en donnant le résultat d’affichage.

15
Résultat :

………………………………………
import java.util.ArrayList; List<String> sousListe = liste.subList(1, 4);
import java.util.List; ……………………………………… afficherListe("sous liste", sousListe);
……………………………………… System.out.println("");
………………………………………
public class TestSubList {
public static void afficherListe(final
…………………………………… String nom, sousListe.remove(1);
final List<String> sousListe) { afficherListe("liste",liste);
int i = 0; System.out.println("");
for (String element : sousListe) {
System.out.format("%s %2d : %s\n", nom, i, afficherListe("sous liste", sousListe);
element);
i++; } } System.out.println("");
public static void main(final String[] args) { liste.remove(1);
List<String> liste = new ArrayList<String>(); afficherListe("liste", liste);
liste.add("COURS PO AVANCEE"); System.out.println("");
liste.add("COURS PROGRAMMATION WEB");
liste.add("ATELIER PO AVANCEE"); afficherListe("sous liste", sousListe);
liste.add("ATELIER WEB "); System.out.println("");} }
liste.add("TD PO AVANCEE");

Note :

 Il est préférable d'utiliser un Itération pour parcourir les éléments d'une collection de type
List plutôt que de faire une boucle sur son nombre d'éléments et d'obtenir chaque élément en
utilisant son indice.
 Le framework propose des classes qui implémentent l'interface List : Vector, ArrayList,
LinkedList et CopyOnWriteArrayList.

5. La classe ArrayList
Java fournit une classe ArrayList qui peut être utilisée pour créer des conteneurs qui stockent des listes
d'objets.

La classe ArrayList offre certains avantages par rapport à la classe Arrays. Plus précisément,
une ArrayList est redimensionnable dynamiquement, ce qui signifie que sa taille peut changer pendant
l'exécution du programme. Cela signifie que :

 Vous pouvez ajouter un élément à tout moment dans un conteneur ArrayList. La taille du
tableau se développe automatiquement pour s'adapter au nouvel élément.
 Vous pouvez supprimer un élément à tout moment dans un conteneur ArrayList et la taille du
tableau se contracte automatiquement.

Pour utiliser la classe ArrayList, vous devez utiliser l'une des instructions d'importation suivantes:

16
import java.util.ArrayList;//ou
import java.util.*;

Ensuite, pour déclarer une ArrayList, vous pouvez utiliser le constructeur par défaut, comme dans
l’exemple suivant qui déclare une liste de String

ArrayList< String> names = new ArrayList< String>() ;

Le constructeur par défaut crée une ArrayList avec une capacitée de 10 éléments. La capacité
d'une ArrayList est le nombre d'éléments qu'elle peut tenir sans avoir à augmenter sa taille. Par
définition, la capacité d’une ArrayList est supérieure ou égale à sa taille.

Vous pouvez également spécifier une capacité si vous le souhaitez. L’exemple suivant déclare
une ArrayList qui peut contenir 20 noms.

ArrayList< String> noms = new ArrayList< String>(20);

Note :

 Si vous savez que vous aurez besoin de plus de 10 éléments au départ, il est plus efficace de créer
une liste de tableaux avec une plus grande capacité.

Le tableau suivant résume quelques méthodes utiles de la classe ArrayList.

Méthode Description
public void add(Object) Ajouter un élément à une ArrayList; la version par défaut
public void add(int, ajoute un élément au prochain emplacement disponible;
Object) une version surchargée vous permet de spécifier une
position à laquelle nous voulons ajouter l'élément
public void remove(int) Supprimer un élément d'une ArrayList à un emplacement
spécifié
public void set(int, Object) Modifier un élément à un emplacement spécifié dans une
ArrayList
Object get(int) Récupérer un élément d'un emplacement spécifié dans une
ArrayList
public int size() Renvoyer la taille actuelle de ArrayList

Note : Différences entre Tableaux et ArrayList

 Un tableau est une fonctionnalité de base fournie par Java. ArrayList fait partie du Framework
Collection en Java. Par conséquent, les membres du tableau sont accessibles via [], tandis que
ArrayList dispose d'un ensemble de méthodes pour accéder aux éléments et les modifier.
 Le tableau est une structure de données de taille fixe, contrairement à ArrayList. Il n'est pas
nécessaire de mentionner la taille d'ArrayList lors de sa création. Même si nous spécifions une
capacité initiale, nous pouvons ajouter plus d'éléments.

17
 Un tableau peut contenir à la fois des types de données primitifs et des objets d'une classe, en
fonction de la définition du tableau. Cependant, ArrayList ne prend en charge que les objets
d’une classe, pas les types de données primitifs.
Lorsque nous faisons arraylist.add(1) ; elle convertit le type de données primitif int en un
objet Integer.
 Puisque ArrayList ne peut pas être créé pour les types de données primitifs, les membres de
ArrayList sont toujours des références à des objets à différents emplacements de mémoire. Par
conséquent, dans ArrayList, les objets réels ne sont jamais stockés à des endroits contigus, mais
les références des objets réels sont stockées à des endroits contigus
 Dans les tableaux, cela dépend si les tableaux sont de type primitif ou de type objet. Dans le cas
de types primitifs, les valeurs réelles sont stockées dans des emplacements contigus, mais dans le
cas d'objets, l'allocation est similaire à ArrayList.

Exercice d’application 2 :
Trier une ArrayList à l'aide de la méthode Collections.sort() et en fournissant ArrayList comme
argument. Pour utiliser cette méthode, vous devez importer le package java.util.Collections.
Solution
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String args[]) {
ArrayList< Integer> liste = new ArrayList< Integer>();
liste.add(4);
liste.add(5);
liste.add(2);
System.out.println("Liste non triée : " + liste);
Collections.sort(liste);
System.out.println("liste triée : " + liste); }}
Exercice d’application 3 :
1. Créer un programme Java qui crée une collection (ArrayList) de noms de villes puis alimenter
cette collection avec quelques valeurs et afficher la taille de la collection
Exemple de résultat à obtenir :
La collection contient 4 villes !

2. Compléter le programme pour afficher le contenu de la collection.

Exemple de résultat à obtenir :


La collection contient 4 villes !
Kasserine
Feriana
Thala
Thelepte

3. Trouver une méthode pour vider la collection et modifier votre programme pour afficher un
message d’erreur lorqu’elle est vide et afficher le contenu lorsqu’elle n’est pas vide.

18
 Après avoir de nouveau alimenté votre liste de villes, modifiez le nom d’une ville et
affichez de nouveau la liste des villes.
Conseil : Pour modifier le nom, il faut supprimer un élément (remove) et en ajouter un autre (add)
4. Triez votre collection et ré-affichez la liste des villes. Pour trier notre collection, il faut utiliser
la méthode « sort ». Pour le moment, utilisons la syntaxe suivante
« Collections.sort(uneArrayList) » pour trier une ArrayList.
Solution
import java.util.* ;
public class CollectionVille{
public static void main(String[] args){

ArrayList villes = new ArrayList();


villes.add("Kasserine");
villess.add("Feriana");
villes.add("Thelepte");
villes.add("Thala");
System.out.println("La collection creee contient "+ villes.size()+" villes !");
affiche(villes);
villes.clear();
affiche(villes);
villes.add("Hidra");
String ville = "Feriana";
if (villes.contains(ville)){
System.out.println("la ville " + ville + " fait partie de la liste");
}
else {
System.out.println("la ville "+ville+" ne fait pas partie de la liste");
}

ville = "Thelepte";
if (ville.contains(ville)){
System.out.println("la ville "+ville+" fait partie de la liste");
}
else{
System.out.println("la ville "+ville+" ne fait pas partie de la liste");
}
affiche(villes);
villes.remove("Thala");
villes.add("Foussana");
affiche(villes);
Collections.sort(villes);
affiche(villes);
}
// Méthode affiche

19
static void affiche(ArrayList ville){
if ( ! villes.isEmpty()){
for (int i=0;i<villes.size() ;i++ ){
System.out.println(villes.get(i));
}
}
else{
System.out.println("Liste vide");
}
}

6. L'interface Set

L'interface Set définit les fonctionnalités d'une collection qui ne peut pas contenir de doublons dans
ses éléments. Une collection de type Set peut contenir un objet null mais cela dépend des
implémentations. Certaines d'entre-elles ne permettent pas l'ajout de null.

Les éléments ajoutés dans une collection de type Set doivent réimplémenter leurs méthodes equals()
et hashCode(). Ces méthodes sont utilisées lors de l'ajout d'un élément pour déterminer s'il est déjà
présent dans la collection.

Note :

La valeur retournée par hashCode() est recherchée dans la collection :

 Si aucun objet de la collection n'a la même valeur de hachage alors l'objet n'est pas encore
dans la collection et peut être ajouté
 Si un ou plusieurs objets de la collection ont la même valeur de hachage alors la méthode
equals() de l'objet à ajouter est invoquée sur chacun des objets pour déterminer si l'objet est
déjà présent ou non dans la collection

L'interface définit plusieurs méthodes [3].:

Méthode Rôle
boolean add(E e) Ajouter l'élément fourni en paramètre à la collection si
celle-ci ne le contient pas déjà et renvoyer un booléen
qui précise si la collection a été modifiée
boolean addAll(Collection<? Ajouter tous les éléments de la collection fournie en
extends E> c) paramètre à la collection si celle-ci ne les contient pas
déjà et renvoyer un booléen qui précise si la collection a
été modifiée
void clear() Retirer tous les éléments de la collection
Boolean contains(Object o) Renvoyer un booléen qui précise si la collection contient

20
l'élément fourni en paramètre
boolean Renvoyer un booléen qui précise si tous les éléments de
containsAll(Collection<?> c) la collection fournie en paramètre sont contenus dans la
collection
boolean equals(Object o) Comparer l'égalité de la collection avec l'objet fourni en
paramètre. L'égalité est vérifiée si l'objet est de type Set,
que les deux collections ont le même nombre d'éléments
et que chaque élément d'une collection est contenu dans
l'autre
int hashCode() Retourner la valeur de hachage de la collection
boolean isEmpty() Renvoyer un booléen qui précise si la collection est vide
Iterator<E> iterator() Renvoyer un Iterator sur les éléments de la collection
boolean remove(Object o) Retirer l'élément fourni en paramètre de la collection si
celle-ci le contient et renvoyer un booléen qui précise si
la collection a été modifiée
boolean Retirer les éléments fournis en paramètres de la
removeAll(Collection<?> c) collection si celle-ci les contient et renvoyer un booléen
qui précise si la collection a été modifiée.
boolean Retirer tous les éléments de la collection qui ne sont pas
retainAll(Collection<?> c) dans la collection fournie en paramètre
int size() Renvoyer le nombre d'éléments de la collection. Si ce
nombre dépasse Integer.MAX_VALUE alors la valeur
retournée est MAX_VALUE
Object[] toArray() Renvoyer un tableau des éléments de la collection
<T> T[] toArray(T[] a) Renvoyer un tableau des éléments de la collection dont
le type est celui fourni en paramètre

Note :

 Il est possible d'utiliser un Iterator pour parcourir les éléments de la collection.


 L'invocation de la méthode add() avec en paramètre un élément déjà présent dans la
collection n'aucun effet.
 L'interface Set possède deux interfaces filles : SortedSet et NavigableSet.
 L'API Collections propose plusieurs implémentations de l'interface Set :
ConcurrentSkipListSet, CopyOnWriteArraySet, EnumSet, HashSet, LinkedHashSet et
TreeSet.

7. La classe HachSet
La bibliothèque Collections Java fournit une classe HashSet qui implémente un Set basé sur une table de
hachage (HashTable). Voici la liste des constructeurs fournis par la classe HashSet.

Constructeur Description

21
HashSet() Ce constructeur construit un HashSet par défaut.
HashSet(Collection c) Ce constructeur initialise le hash set en utilisant les Out
éléments de la collection c. re
HashSet(int capacity) Ce constructeur initialise la capacité du hachage défini les
sur la valeur entière donnée. La capacité augmente mét
automatiquement à mesure que des éléments sont hod
ajoutés au HashSet. es
HashSet(int capacity, float fillRatio) Ce constructeur initialise à la fois la capacité et le taux hér
de remplissage (load capacity) de HashSet à partir de itée
sesarguments. s
Ici, le taux de remplissage doit se situer entre 0,0 et 1,0, de
et il détermine la quantité de HashSet avant de le ses
redimensionner vers le haut. Plus précisément, lorsque cla
le nombre d'éléments est supérieur à la capacité du sse
HashSet multipliée par son taux de remplissage, le s
HashSet est élargi. mè
res,
HashSet définit les méthodes suivantes :

Méthode Description
boolean add(Object o) Ajouter l'élément spécifié à HashSet s'il n'est pas déjà présent. Ex
boolean isEmpty() Retourner true si cet HashSet ne contient aucun élément. erc
Iterator iterator() Retourner un itérateur sur les éléments de cet HashSet. ice
boolean remove(Object o) Supprimer l'élément spécifié de cet HashSet s'il est présent. d’a
int size() Retourner le nombre d'éléments. ppl
void clear() Supprimer tous les éléments. ica
tio
boolean contains(Object o) Retourner true si cet HashSet contient l'élément spécifié.
n
4:
1. Créer un programme Java qui crée une collection (HashSet) de noms de villes puis
alimenter cette collection avec quelques valeurs, essayer d’utiliser des doublons.
2. Compléter le programme pour afficher le contenu de la collection.
3. Trouver une méthode pour vérifier l’existence d’une ville donnée
Supprimer une ville et affichez de nouveau la liste des villes.
Solution
import java.util.HashSet; System.out.println("Est ce que la ville
import java.util.Iterator; kasserine:" + villes.contains("Kasserine"));
// Suppression d'éléments de HashSet à
public class Test { //l'aide de remove ()
public static void main(String args[]) { villes.remove("Feriana");
HashSet< String> villes = new HashSet< String>(); System.out.println("Liste après avoir retiré
// Ajouter des éléments dans HashSet en utilisant Feriana:" + villes);
//add() // Afficher HashSet

22
villes.add("Kasserine"); System.out.println("Itérer sur villes:");
villes.add("Feriana"); Iterator< String> it = villes.iterator();
villes.add("Thala"); while (it.hasNext())
villes.add("Hidra"); System.out.println(it.next());
villes.add("Thelepte"); }
villes.add("Feriana");// ajouter un élément en }
//double
// Afficher HashSet
System.out.println(villes);
Exercice d’application 5:
1. Créer un programme Java qui crée une collection (ArrayList) de noms de villes puis
alimenter cette collection avec quelques valeurs.(voir Activité 1)
2. Créer un programme Java qui crée une collection (HashSet) de noms de villes puis
alimenter cette collection à partir de la collection précédente.
3. Ajouter d’autres valeurs.
4. Compléter le programme pour afficher le contenu de la collection.

Solution HashSet< String> set = new HashSet< String>(list);


import java.util.HashSet; set.add("France");
import java.util.Iterator; Iterator< String> i = set.iterator();
import java.util.ArrayList; while (i.hasNext()) {
System.out.println(i.next());
public class Test { }
public static void main(String }
args[]) { }
ArrayList< String> list = new
ArrayList< String>();
list.add("Maroc");
list.add("Tunisie");
list.add("Algérie");

Chapitre 3 Gestion des entrées/sorties(Les flots de base en java)


Objectifs

 Présenter les flots de base en java, 23


 Savoir manipuler les méthodes de flots InputStream et OutputStream,
 Savoir manipuler les méthodes de flots DataInputStream et
DataOutputStream,
Dans ce chapitre, nous allons examiner comment le langage Java gère les Entrées/Sorties par le biais de
flots (Stream). Par la suite, nous approfondirons le maniement des fichiers et des données qui s’y
trouvent.

1. Les fondements de la notion de flot


Un flot est soit une source d’octets, soit une destination pour les octets. L’ordre est important. Par
exemple, un programme souhaitant lire à partir d’un clavier peut se servir d’un flot pour mener à bien
cette action.

Il existe deux catégories fondamentales de flots, à savoir les flots d’entrée, à partir desquels on peut lire
et les flots de sortie qui, au contraire, acceptent l’écriture mais ne peuvent être lus.

Dans le package java.io, certains flots ont pour origine une ressource, ils peuvent lire ou écrire dans une
ressource déterminée telle qu’un fichier ou une zone mémoire. D’autres flots sont appelés filtres.

Un filtre d’entrée est créé moyennant une connexion à un flot d’entrée existant, de sorte que, lorsque
vous tentez de lire à partir du filtre d’entrée, vous obteniez les données extraites, à l’origine, sur cet
autre flot d’entrée[4][5].

La figure suivante illustre une relation hiérarchique partielle de certaines des classes utilisées par Java
pour les opérations d'entrée et de sortie (E/S) [4]. :

24
Classe Description
InputStream Classe abstraite contenant des méthodes pour effectuer des entrées
(E)
FileInputStream Enfant de InputStream qui offre la possibilité de lire à partir de
fichiers sur disque
BufferedInputStream Enfant de FilterInputStream, qui est un enfant
de InputStream; BufferedInputStream gère les entrées à partir du
périphérique d’entrée standard (ou par défaut) du système,
généralement le clavier.
OutputStream Classe abstraite contenant des méthodes pour effectuer une sortie
(S)
FileOutputStream Enfant de OutputStream qui vous permet d'écrire sur des fichiers de
disque
BufferedOutputStream Enfant de FilterOutputStream, qui est un enfant
de OutputStream; BufferedOutputStream gère les entrées provenant
du périphérique de sortie standard (ou par défaut) du système,
généralement le console.
PrintStream Enfant de FilterOutputStream, qui est un enfant
de OutputStream; System.out est un objet PrintStream
Reader Classe abstraite pour la lecture de flux de caractères; les seules
méthodes qu'une sous-classe doit implémenter sont read(char[], int,
int) et close()
BufferedReader Lit le texte à partir d'un flux d'entrée de caractères et met en
mémoire tampon les caractères
BufferedWriter Écrit du texte dans un flux de sortie de caractères en mettant en
mémoire tampon les caractères pour permettre une écriture efficace
des caractères, des tableaux et des lignes

25
2. Les flots d’entrée/sortie
2.1.InputStream et OutputStream

Méthodes InputStream

int read()
int read(byte[])
int read(byte[], int, int)

Note :

Ces trois méthodes fournissent des octets[5]. :

 La méthode read renvoie un argument int contenant un octet lu à partir du flot ou la valeur -1
indiquant la fin de fichier.
 Les deux méthodes restantes remplissent une table d’octets avec des octets lus et en renvoient le
nombre. Les deux arguments int de la troisième méthode indiquent un sous-ensemble de la table
cible.

Note :

Pour profiter d’une efficacité optimale, lisez toujours les données par blocs les plus grands possible.

void close() : Il est recommandé de fermer un flot lorsque vous avez fini de l’utiliser.

int available() : Cette instruction signale le nombre d’octets prêts à être lus dans le flot.
Une opération de lecture réelle succédant à cet appel peut éventuellement renvoyer plus
d’octets.

skip(long) : Cette méthode permet de “sauter” un nombre déterminé d’octets provenant du


flot.
Note :

Ces méthodes visent à effectuer des opérations de "rejet" sur un flot à condition que celui-ci les prenne
en charge :

 La méthode markSupported() renvoie true si les méthodes mark() et reset() sont


opérationnelles dans le cadre de ce flot spécifique.
 La méthode mark(int) sert à indiquer que le point courant dans le flot devrait être noté et qu’il
faudrait affecter une quantité suffisante de mémoire tampon, dans le but d’admettre au moins le
nombre de caractères de l’argument donné.

26
 A la suite d’opérations read() successives, la méthode reset() tend à repositionner le flot
d’entrée sur le premier point mémorisé.

Vous pouvez utiliser OutputStream pour écrire tout ou partie d'un tableau d'octets. Lorsque vous avez fini
d'utiliser un OutputStream, vous souhaitez généralement le vider et le fermer.

Méthodes OutputStream

write(int)
write(byte[])
write(byte[], int, int)

Note :

Ces méthodes écrivent dans le flot de sortie. A l’instar des flots d’entrée, il est recommandé d’écrire
les données par blocs les plus grands possibles.

close() : Il est préférable de fermer les flots de sortie après avoir terminé de les utiliser.

flush() :Il arrive parfois que le flot de sortie tamponne les écritures avant de les écrire réellement.
La méthode flush() vous donne les moyens de purger les buffers.

Exercice d’application 1 :
Utiliser un flot de sortie pour écrire la chaine "Hello, world".
Solution
import java.io.*;
public class Test {
public static void main(String args[]) {
String s = "Hello, world";
// convertit String en un tableau d'octets
byte[] data = s.getBytes();
OutputStream output = null;
try {
output = System.out;
output.write(data);
output.flush();
output.close();
} catch (Exception e) {
System.out.println("Erreur : " + e); }}}

Résultat
Hello, world

27
2.2.DataInputStream et DataOutputStream
Ces filtres permettent la lecture et l’écriture de types de base Java au moyen de flots. Voici une palette
de méthodes spéciales pour les types de base :

Méthodes DataInputStream

byte readByte()
long readLong()
double readDouble()
Méthodes DataOutputStream

void writeByte(byte)
void writeLong(long)
void writeDouble(double)

Note :

Notez que les méthodes de DataInputStream vont de pair avec les méthodes de DataOutputStream.

3. Les flots de caractères : Readers et Writers


3.1.Le format Unicode
En interne Java utilise le format Unicode, comme ces caractères sont représentés sur 16 bits on est
obligé d’utiliser des flots spéciaux pour les manipuler: ce sont les Reader et les Writer.

Les classes InputStreamReader et OutputStreamWriter font le pont avec les flots d’octets en assurant de
manière implicite ou explicite les conversions nécessaires.

3.2.Octet <-> Conversion de caractères


Par défaut, si vous construisez simplement un Reader ou un Writer connecté à un flot, les règles de
conversion qui s’appliquent sont celles entre le codage de la plateforme locale et Unicode. Dans la
plupart des pays européens utilisant les caractères "latins", l’encodage des caractères suit la norme ISO
8859-1.(“Cp1252” sous Windows).

Vous pouvez sélectionner un autre type de codage d’octets, à l’aide d’une des listes regroupant les
formes de codage reconnues que vous trouverez dans la documentation pour l’outil native2ascii.

Pour lire une entrée à partir d’un codage de caractère non local ou même la lire à partir d’une connexion
réseau avec un type différent de machine, vous pouvez construire un InputStreamReader par le biais
d’un codage de caractères explicite comme suit :

ir = new InputStreamReader(flotentree, "ISO8859_1")

Note :

28
Si vous lisez les caractères d’une connexion réseau, nous vous enjoignons d’utiliser cette formulation,
faute de quoi votre programme sera toujours tenté de convertir les caractères qu’il lit comme s’il
s’agissait d’une représentation locale, ce qui ne serait pas le reflet de la réalité.

3.3.BufferedReader et BufferedWriter
Il est préférable d’enchaîner un BufferedReader ou un BufferedWriter, sur un InputStreamReader ou
InputStreamWriter car la conversion entre formats donne des résultats plus probants lorsqu’elle est
effectuée par blocs. N’oubliez pas d’utiliser la méthode flush () sur un BufferedWriter.

Exemple d’utilisation : Lecture de chaîne d’entrées


public class CharInput {
public static void main(String args[]) {
String s;
InputStreamReader ir;
BufferedReader in;
ir = new InputStreamReader(System.in);
in = new BufferedReader(ir);
while ((s = in.readLine()) != null) {
System.out.println("Read: " + s);
}
}}

Chapitre 4 Gestion des entrées/sorties (Les classes Path et File en java)

Objectifs

 Présenter les principes d’E /S en java,


 Connaitre les caracteristiques des classes Path et File en java,
 Savoir manipuler les fichers en java en29lecture et en écriture,
 Manipuler les fiches à accès aléatoire.

On utilise les classes Java Path et Files pour travailler avec des fichiers.

 La classe Path permet de créer des objets contenant des informations sur les fichiers et les
répertoires, tels que leurs emplacements, leurs tailles, leurs dates de création et même leur
existence.
 La classe Files est utilisée pour effectuer des opérations sur les fichiers et les répertoires, tels que
les supprimer, déterminer leurs attributs et créer des flux d'entrée et de sortie.
Vous pouvez inclure l'instruction suivante dans un programme Java pour utiliser les
classes Path et Files:

import java.nio.file.*;

Note :

nio dans java.nio signifie nouvelle entrée/sortie car ses classes sont «nouvelles» en ce sens qu’elles
n’ont pas été développées avant Java 7.

1. Utilisation des classes path


1.1.Créer un chemin
Pour créer un chemin d'accès, vous devez d'abord déterminer le système de fichiers par défaut sur
l'ordinateur hôte à l'aide d'une instruction telle que:

FileSystem fs = FileSystems.getDefault();

Cette instruction crée un objet FileSystem à l'aide de la méthode getDefault() de la classe FileSystems.
La déclaration utilise deux classes différentes. La classe FileSystem, sans s, est utilisée pour instancier
l'objet.

FileSystems, avec s, est une classe qui contient des méthodes fabrique (factory methods), qui aident à la
création d'objets.Après avoir créé un objet FileSystem, vous pouvez définir un chemin en utilisant la
méthode getPath() avec:

Path chemin = fs.getPath("C:\\Documents \\INFO\\POAVANCEE.txt");

30
Rappel :

Rappelez-vous que la barre oblique inverse est utilisée dans le cadre d'une séquence d'échappement en
Java. (Par exemple, '\ n' représente un caractère de nouvelle ligne.) Ainsi, pour saisir une barre oblique
inverse en tant que délimiteur de chemin dans une chaîne, vous devez taper deux barres obliques
inverses pour indiquer une seule barre oblique inversée.

Une alternative consiste à utiliser la méthode getSeparator() de la classe FileSystem. Cette méthode
renvoie le séparateur correct pour le système d'exploitation actuel. Par exemple, vous pouvez créer un
chemin identique au précédent en utilisant une instruction telle que la suivante

Path chemin = fs.getPath("D:" + fs.getSeparator() + "Documents" +fs.getSeparator() + "INFO"


+ fs.getSeparator() +"POAVANCEE.txt");
Une
autr
e façon de créer un chemin consiste à utiliser la classe Paths (notez que le nom se termine par s). La
classe Paths est une classe d'assistance qui élimine la nécessité de créer un objet FileSystem. La
méthode get() de la classe Paths appelle la méthode getPath() du système de fichiers par défaut sans

Path chemin = Paths.get("C:\\Documents \\INFO\\POAVANCEE.txt");

vous obliger à instancier un objet FileSystem. Vous pouvez créer un objet Path à l'aide de l'instruction
suivant :

Une fois le chemin créé, vous utilisez son identificateur (dans ce cas, chemin) pour faire référence au
fichier et y effectuer des opérations.

1.2.Récupérer des informations sur un chemin


Le tableau suivant récapitule plusieurs méthodes de classe Path utiles.

Méthode Description Note :


String toString() Renvoyer la représentation de la chaîne du chemin, en
éliminant les doubles barres obliques inverses.  Le
Path getFileName() Renvoyer le fichier ou le répertoire désigné par ce chemin; c'est s éléments
le dernier élément de la séquence d'éléments nommés d’un
int getNameCount() Renvoyer le nombre d'éléments nommés dans le chemin. chemin
Path getName(int) Renvoyer le nom dans la position du chemin spécifié par le sont
paramètre entier accessible
s via un index. L'élément de niveau supérieur de la structure du répertoire est situé à l'index 0.
 L'élément le plus bas de la structure est accessible par la méthode getName() et possède un
index égal à un de moins que le nombre d'éléments de la liste. Vous pouvez utiliser la

31
méthode getNameCount() pour extraire le nombre de noms de la liste et la
méthode getName(int) pour extraire le nom à la position spécifiée par l'argument.

Exercice d’application 1 :
Pour le fichier POAVANCEE :
1. Afficher son chemin
2. Afficher son nom en utilisant la méthode getFileName()
3. Afficher le nombre des éléments dans ce chemin et afficher le nom de chaque élément.
Solution

import java.nio.file.*;
public class Test {
public static void main(String args[]) {
Path chemin = Paths.get("/Documents/POAVANCEE.txt");
int count = chemin.getNameCount();
System.out.println("le chemin est " + chemin.toString());
System.out.println("le nom du fichier est " + chemin.getFileName());
System.out.println("Il y a " + count + " éléments dans ce chemin");
for (int x = 0; x < count; x++)
System.out.println("Elément " + x + " : " + chemin.getName(x));
}
}
Résultat
le chemin est / Documents/POAVANCEE.txt
le nom du fichier est intro.txt
Il y a 2éléments dans ce chemin
Elément 0 : Documents
Elément 1 : POAVANCEE

1.3.Vérification de l'accessibilité des fichiers


Pour vérifier qu'un fichier existe et que le programme peut y accéder si nécessaire, vous pouvez utiliser
la méthode checkAccess(). L'instruction d'importation suivante vous permet d'accéder à des constantes
pouvant être utilisées comme arguments de la méthode[6].:

import static java.nio.file.AccessMode.*;

En supposant que vous ayez déclaré un chemin nommé monchemin, la syntaxe que vous utilisez
avec checkAccess() est la suivante:

monchemin.getFileSystem().provider().checkAccess();

32
Note :
Vous pouvez utiliser l'un des éléments suivants comme arguments de la méthode checkAccess():
 Aucun argument : Vérifie que le fichier existe
 READ : vérifie que le fichier existe et que le programme est autorisé à le lire.
 WRITE : vérifie que le fichier existe et que le programme est autorisé à écrire dans le fichier.
 EXECUTE : Vérifie que le fichier existe et que le programme est autorisé à exécuter le fichier
 Vous pouvez utiliser plusieurs arguments pour la méthode checkAccess(), séparés par des
virgules. Si le fichier nommé dans l'appel de méthode est inaccessible, une
exception IOException est levée.

Exercice d’application 2 :
Dans une classe TestAccess, donnez le morceau du code qui vérifie le mode d’accès de fichier
POAVANCEE
Solution
import java.io.IOException;
import java.nio.file.*;
import static java.nio.file.AccessMode.*;
public class Test {
public static void main(String args[]) {
Path chemin = Paths.get("POAVANCEE.txt");
try {
chemin.getFileSystem().provider().checkAccess(chemin, READ, EXECUTE);
System.out.println("Le fichier peut être lu et exécuté");
} catch (IOException e) {
System.out.println("Le fichier ne peut pas être utilisé");
} }}
Résultat
Le fichier ne peut pas être utilisé
-rw-r--r-- 1 laila admin 12 14 Sep 02:19 intro.txt

1.4.Suppression d'un chemin


La méthode delete() de la classe Files accepte un paramètre Path et supprime le dernier élément (fichier
ou répertoire) d'un chemin ou lève une exception en cas d'échec de la suppression. Par exemple:

 Si vous essayez de supprimer un fichier qui n'existe pas, une exception


 NoSuchFile Exception est levée.
 Un répertoire ne peut être supprimé que s'il est vide. Si vous essayez de supprimer un répertoire
contenant des fichiers, une exception DirectoryNotEmptyException est levée.
 Si vous essayez de supprimer un fichier sans y avoir la permission, une
exception SecurityException est levée.
 D'autres erreurs d'entrée/sortie entraînent une exception IOException.

33
Exercice d’application 3 :
Dans une classe Test, donnez le morceau du code qui tente de supprimer le fichier
POAVANCEE

Solution
import java.io.IOException;
import java.nio.file.*;

public class Test {


public static void main(String args[]) {
Path chemin = Paths.get("POAVANCEE.txt");
try {
Files.delete(chemin);
System.out.println("Le fichier ou le répertoire est supprimé");
} catch (NoSuchFileException e) {
System.out.println("Aucun fichier ou répertoire de ce nom");
} catch (DirectoryNotEmptyException e) {
System.out.println("Le répertoire n'est pas vide");
} catch (SecurityException e) {
System.out.println("Pas de permission pour supprimer");
} catch (IOException e) {
System.out.println("IO exception");
}}
}
Résultat
Le fichier ou le répertoire est supprimé

Note :

La méthode deleteIfExists() de la classe Files peut également être utilisée pour supprimer un fichier,
mais si le fichier n'existe pas, aucune exception n'est levée.

1.5.Attributs de fichier
Vous pouvez utiliser la méthode readAttributes() de la classe Files pour récupérer des informations
utiles sur un fichier. La méthode prend deux arguments - un objet Path et BasicFileAttributes.class - et
renvoie une instance de la classe BasicFileAttributes[6]..

Vous pouvez créer une instance avec une instruction telle que la suivante

BasicFileAttributes attr = Files.readAttributes(chemin, BasicFileAttributes.class);

Après avoir créé un objet BasicFileAttributes, vous pouvez utiliser plusieurs méthodes pour extraire
des informations sur un fichier. Par exemple, la méthode size() renvoie la taille d'un fichier en octets.

34
Des méthodes telles que creationTime() et lastModifiedTime() renvoient la date de création et
modification.

Exercice d’application 4:
Ecrire une classe Test qui affiche l’heure de création, l’heure de la dernière modification et la
taille du ficher POAVANCEE .

Solution
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class Test {


public static void main(String args[]) {
Path chemin = Paths.get("intro.txt");
try {
BasicFileAttributes attr = Files.readAttributes(chemin, BasicFileAttributes.class);
System.out.println("date de création " + attr.creationTime());
System.out.println("date de la dernière modification " + attr.lastModifiedTime());
System.out.println("Taille " + attr.size());

} catch (IOException e) {
System.out.println("IO Exception");
}
}
}
Résultat
heure de création 2019-09-14T01:59:48Z
heure de la dernière modification 2019-09-14T02:00:05.295535Z
Taille 16

2. Lecture et écriture dans un fichier en java


Alors que les utilisateurs considèrent un fichier comme une série d’enregistrements, chaque
enregistrement contenant des champs de données, Java n’attribue pas automatiquement cette
signification au contenu d’un fichier.

Au lieu de cela, Java considère simplement un fichier comme une série d'octets. Lorsque vous effectuez
une opération de saisie dans une application, vous pouvez imaginer les octets entrant dans votre
programme à partir d'un périphérique d'entrée via un flux(stream), qui fonctionne comme un pipeline ou
un canal.

35
2.1.Ecrire dans un fichier
Au lieu d'affecter le périphérique de sortie standard à OutputStream, vous pouvez affecter un fichier.
Pour ce faire, vous pouvez construire un objet BufferedOutputStream et l'affecter à l’OutputStream. Si
vous souhaitez modifier le périphérique de sortie d'une application, vous ne devez pas modifier
l'application mais il faut juste affecter un nouvel objet à l’OutputStream. Le reste de la logique reste le
même.

Java vous permet d'affecter un fichier à un objet Stream afin que la sortie d'écran et la sortie de fichier
fonctionnent exactement de la même manière.

Vous pouvez créer un fichier accessible en écriture à l'aide de la méthode newOutputStream() de la


classe Files. Vous passez un argument Path et un argument StandardOpenOption à cette méthode. La
méthode crée un fichier s'il n'existe pas déjà, ouvre le fichier en écriture et renvoie
un OutputStream qui peut être utilisé pour écrire des octets dans le fichier.

le tableau suivant montre les arguments StandardOpenOption que vous pouvez utiliser comme
deuxième argument de la méthode newOutputStream().

Argument Description

WRITE Ouvre le fichier pour l'écriture

APPEND Ajoute les nouvelles données à la fin du fichier; utiliser cette


option avec WRITE ou CREATE
TRUNCATE_EXISTING Tronque le fichier existant sur 0 octet pour que le contenu du
fichier soit remplacé; utiliser cette option avec l'option WRITE

CREATE_NEW Crée un nouveau fichier seulement s’il n’existe pas; lève une
exception si le fichier existe déjà
CREATE Ouvre le fichier s'il existe ou crée un nouveau fichier sinon.

DELETE_ON_CLOSE Supprime le fichier lorsque le flux est fermé;


Si vous ne spécifiez aucune option et que le fichier n'existe pas, un nouveau fichier est créé. Si le fichier
existe, il est tronqué. En d'autres termes, ne spécifier aucune option revient à
spécifier CREATE et TRUNCATE_EXISTING.

Exercice d’application 5 :
On veut écrire la phrase Hello,DSI31 dans le fichier intro.txt,utiliser la méthode write de
l’objet BufferedOutputStream .
Utiliser la méthode suivante pour convertir une chaine (s) en un tableau d'octets :
byte[] data = s.getBytes();
Solution

36
import java.io.*;
import java.nio.file.*;
// charger les options
import static java.nio.file.StandardOpenOption.*;

public class Test {


public static void main(String args[]) {
Path chemin = Paths.get("intro.txt");
String s = "Hello, DSI31";

// convertit String en un tableau d'octets


byte[] data = s.getBytes();

OutputStream output = null;


try {
// Un objet BufferedOutputStream est affecté à la référence OutputStream.
output = new BufferedOutputStream(Files.newOutputStream(chemin, CREATE));
// Ecrire dans le fichier
output.write(data);

// vider le tampon
output.flush();

// fermer le fichier
output.close();

} catch (Exception e) {
System.out.println("Message " + e);
}
}
}
Résultat
// contenu de intro.txt
Hello, DSI31

2.2.Lecture d'un fichier

Vous utilisez un InputStream comme vous utilisez un OutputStream. Pour ouvrir un fichier en
lecture, vous pouvez utiliser la méthode newInputStream() de la classe Files. Cette méthode accepte un
paramètre Path et renvoie un flux capable de lire des octets à partir d'un fichier.

Exemple : Lecture d’un fichier

37
import java.io.*;
import java.nio.file.*;

public class Test {


public static void main(String args[]) {
Path chemin = Paths.get("intro.txt");
InputStream input = null;
try {
input = Files.newInputStream(chemin);

BufferedReader reader = new BufferedReader(new InputStreamReader(input));


String s = null;
s = reader.readLine();
System.out.println(s);
input.close();

} catch (IOException e) {
System.out.println("Message " + e);
}
}
}

3. Fichiers à accès aléatoire en java

Pour de nombreuses applications, l'accès séquentiel est inefficace. Des applications nécessitent l'accès
immédiat à un enregistrement pendant qu'un client est en attente.

Vous pouvez utiliser la classe FileChannel de Java pour créer vos propres fichiers à accès aléatoire. Un
objet FileChannel(fichier du canal) est un moyen de lire et d’écrire un fichier. Un FileChannel peut
être recherché, ce qui signifie que vous pouvez rechercher un emplacement de fichier spécifique et que
les opérations peuvent commencer à n’importe quel emplacement spécifié.

Le tableau suivant décrit certaines méthodes la classe FileChannel.

Méthode Description
FileChannel open(Path file, Ouvre ou crée un fichier et renvoie un canal de
OpenOption... options) fichier pour accéder au fichier.
long position() Renvoie la position du fichier du canal
FileChannel position(long newPosition) Définit la position du fichier du canal
int read(ByteBuffer buffer) Lit une séquence d'octets du canal dans la mémoire

38
tampon (buffer)
long size() Renvoie la taille du fichier du canal
int write(ByteBuffer buffer) Écrit une séquence d'octets sur le canal à partir du
tampon

Note :

Un tableau d'octets peut être encapsulé ou englobé dans un ByteBuffer à l'aide de la méthode wrap() de
la classe ByteBuffer. La création d'un FileChannel utilisable pour l'écriture aléatoire de données
nécessite la création d'un ByteBuffer et plusieurs autres étapes :

 Vous pouvez utiliser la méthode newByteChannel() de la classe Files pour obtenir


un ByteChannel pour un chemin. La méthode newByteChannel() accepte les
arguments Path et StandardOpenOption qui spécifient le mode d’ouverture du fichier.
 Le ByteChannel renvoyé par la méthode newByteChannel() peut ensuite être converti
en FileChannelà l'aide d'une instruction similaire à celle-ci.

FileChannel fc = (FileChannel)Files.newByteChannel(file, READ, WRITE);

 Vous pouvez créer un tableau d'octets. Par exemple, un tableau d'octets peut être construit à
partir d'une chaîne en utilisant la méthode getBytes()comme suit :
String s = "Hello, world";
byte[] donnees = s.getBytes();
 Le tableau d'octets peut être encapsulé dans un ByteBuffercomme suit:
ByteBuffer out = ByteBuffer.wrap(data);

 Ensuite, le ByteBuffer rempli peut être écrit dans le FileChanneldéclaré avec une instruction telle
que la suivante:
fc.write(out);

 Vous pouvez vérifier si le contenu d'un ByteBuffer a été utilisé à l’aide de la


méthode hasRemaining()
 Après avoir écrit le contenu d'un ByteBuffer, vous pouvez réécrire le même contenu en utilisant
la méthode rewind() pour repositionner le ByteBuffer au début du tampon.

Exercice d’application 6:
Supposons que le ficher POAVANCEE contient la phrase suivante : Le cours programmation
objet avancee, on veut écrire le mot Hello aux positions 0 et 22.

Solution
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;

39
public class Test {
public static void main(String args[]) {
Path chemin = Paths.get("POAVANCEE.txt");
String s = "Hello";
byte[] data = s.getBytes();
ByteBuffer out = ByteBuffer.wrap(data);
FileChannel fc = null;
try {
fc = (FileChannel) Files.newByteChannel(chemin, READ, WRITE);
fc.position(0);
while (out.hasRemaining())
fc.write(out);

out.rewind();
fc.position(22);

while (out.hasRemaining())
fc.write(out);

fc.close();
} catch (Exception e) {
System.out.println("Erreur : " + e);
}
}
}
Résultat
le contenu du fichier après l'exécution du programme
Hellours programmationHellot avancee

Chapitre 5 Les threads

Objectifs

 Se familiariser avec la notion des threads en java,


 Définir les caractéristiques d’un thread et savoir les utiliser,
 Savoir et comprendre le mécanisme de la programmation parallele.

40
Une définition simple, mais utile, d’un ordinateur revient à dire que celui-ci possède une UC qui exécute
le calcul informatique, de la mémoire morte (ROM) contenant le programme exécutant l’UC et de la
mémoire vive (RAM) comprenant les données sur lesquelles le programme opère. Dans ce cas de figure,
une seule tâche peut être exécutée à la fois. Une vision plus approfondie d’un ordinateur moderne admet
la possibilité d’effectuer plusieurs tâches simultanément ou pour le moins donne l’impression qu’il en
est ainsi[7]..

Nous allons considérer un thread ou unité d’exécution comme l’encastrement d’une UC virtuelle avec
son propre code de programmation et ses propres données. La classe java.lang.Thread contenue dans les
bibliothèques de base Java permet la création et le contrôle de nos propres threads.

1. Définition des caractéristiques d'un thread

Un thread comprend trois parties principales: L’UC, le code exécuté par cette UC et finalement les
données avec lesquelles travaille le code.

Les trois parties d’un thread

Avec Java, l’UC virtuelle est incarnée dans la classe Thread. Lors de la mise sur pied d’un thread, ce
dernier envoie le code à exécuter et les données à appliquer par le biais des arguments du constructeur.

Signalons que ces trois aspects sont, en fait, indépendants. Un thread peut exécuter le même code qu’un
autre thread ou un code différent. Il peut, dans la même logique, accéder à des données identiques ou
différentes de celles utilisées par un autre thread[7].

1.1.Attributs de la classe Thread java


Comme pour tous les éléments du langage Java, les threads sont des objets. La classe Thread enregistre
certains attributs d'informations pouvant nous aider à identifier un thread, à connaître son statut ou à
contrôler sa priorité. Ces attributs sont:

 ID : cet attribut stocke un identifiant unique pour chaque thread.

41
 Name : cet attribut stocke le nom du thread.
 Priority : cet attribut stocke la priorité des objets Thread. Les threads peuvent avoir une priorité
comprise entre 1 et 10, 1 étant la priorité la plus basse et 10 la plus élevée. Il n'est pas
recommandé de changer la priorité des threads.
 Status : cet attribut stocke le statut d'un thread. En Java, un thread peut être présent dans l'un des
six états définis dans l'énumération Thread.State: NEW, RUNNABLE, BLOCKED, WAITING,
TIMED_WAITING ou TERMINATED.

La liste suivante spécifie la signification de chacun de ces états :

 NEW : le thread a été créé et il n'a pas encore commencé


 RUNNABLE : le thread est en cours d'exécution dans la machine virtuelle Java
 BLOCKED : le thread est bloqué et attend un moniteur.
 WAITING : le thread attend un autre thread
 TIMED_WAITING : le thread attend un autre thread avec un délai d'attente spécifié
 TERMINATED : le thread a terminé son exécution

Les états d’un Thread

1.2.Méthodes utiles de la classe Thread Java

 Pour mettre en route le thread


o Une fois créé, le thread n’est pas opérationnel. Pour le mettre en service, il est nécessaire
d’appliquer la méthode start(), qui se trouve dans la classe Thread.Une fois cette étape
franchie, l’UC virtuelle représentée dans le thread devient exécutable.
o Une autre méthode issue de la classe Thread, est yield() elle laisse s’exécuter d’autres
threads . Si d’autres threads de même priorité sont exécutables, yield() renvoie le thread
demandeur à la fin de la file d’attente exécutable et laisse ainsi la voie libre pour le
lancement d’un autre thread. La méthode yield() n’est effective qu’à condition qu’il
existe d’autres threads exécutables présentant la même priorité.

42
o A noter que la méthode sleep() permet le lancement de threads de moindre priorité alors
que la méthode yield() n’a d’incidence que sur les threads de même priorité.
 Pour terminer un thread
Lorsqu’un thread a atteint la fin de la méthode run(), il est neutralisé. En clair, l’instance
courante ne peut plus être exécuté. La méthode stop() qui permettait d’arréter un Thread est
considérée comme très dangereuse si elle n’est pas appelée par le Thread courant, pour cette
raison elle a été rendue obsolete par la version 2 de Java.
 Test d’un thread
Il arrive parfois que le thread se trouve dans un état inconnu (ceci se produit si votre code ne
contrôle pas directement un thread particulier). Au moyen de la méthode isAlive(), vous êtes en
mesure de vous renseigner sur la viabilité d’un thread. Cette méthode n’indique pas si le thread
est en cours d’exécution, mais signale qu’il a démarré et qu’un terme n’a pas été mis à son
exécution[7].
 Pour mettre les threads en attente
La méthode join() fait en sorte que le thread en cours attende que le thread sur lequel la méthode
en question est appelée se termine.

2. Eligibilité d’un thread


Le fait que le thread soit devenu exécutable ne signifie pas nécessairement qu’il démarre
instantanément. Sur une machine qui ne possède qu’une UC, il est évident que seule peut être exécutée
une tâche à la fois. Nous allons maintenant examiner plus en détail la façon dont une UC est affectée
lorsqu’il s’agit d’exécuter plusieurs threads [7]

Avec Java, les threads sont d’ordinaire préemptifs sans pour autant être soumis à un partage du temps -
time-slicing-.

La règle régissant les priorités est que beaucoup de threads sont prêts à être exécutés, mais que seul l’un
d’entre eux est effectivement lancé. Ce processus se poursuit tant qu’il est exécutable ou qu’un autre
processus de priorité supérieure devient exécutable. Dans ce dernier cas de figure, le thread de moindre
priorité est devancé par le thread de priorité supérieure.

L’interruption d’un thread peut être imputable à diverses raisons, dont l’appel Thread.sleep() lancé
délibérément afin d’établir une pause ou l’attente d’une entrée/sortie sur un periphérique, fonctionnant
lentement.

Tous les threads exécutables hors service sont conservés dans des files d’attente selon leur priorité. C’est
le premier thread de la file d’attente de priorité supérieure qui est d’abord lancé. Lorsqu’un thread
s’arrête pour des raisons de préemption, son état actuel est conservé et il vient s’ajouter à la file d’attente
en se plaçant à la fin. De même, un thread qui redevient exécutable après avoir été bloqué (en sommeil
ou en attente pour l’E/S par exemple) rejoint toujours la fin de la file d’attente.

Compte tenu que les threads de Java ne sont pas forcément soumis au time-slicing , vous devez veiller à
ce que le code permette le lancement d’autres threads. Pour ce faire, vous pouvez provoquer l’appel de
sleep() .

43
3. Création et exécusion d’un Thread
Chaque programme Java a au moins un thread d'exécution. Lorsque vous exécutez le programme, JVM
exécute le thread d'exécution qui appelle la méthode main() du programme.

Lorsque nous appelons la méthode start() d'un objet Thread, nous créons un autre thread d'exécution.
Notre programme aura autant de threads d'exécution que le nombre d'appels passés à la méthode start().

La classe Thread possède des attributs pour stocker toutes les informations d'un thread. Le planificateur
de système d'exploitation utilise la priorité des threads pour sélectionner celui qui utilise le processeur à
chaque instant et actualise le statut de chaque thread en fonction de sa situation.

Si vous ne spécifiez pas de nom pour un thread, JVM lui attribue automatiquement le nom
suivant: Thread-XX, où XX est un nombre. Vous ne pouvez pas modifier l'ID ou le status d'un thread.

Un programme Java se termine à la fin de tous ses threads (plus précisément à la fin de tous ses threads
non démons). Si le thread initial (celui qui exécute la méthode main()) se termine, le reste des threads
poursuivra leur exécution jusqu'à la fin. Si l'un des threads utilise l'instruction System.exit() pour
terminer l'exécution du programme, tous les threads mettront fin à leur exécution respective.

La création d'un objet de la classe Thread ne crée pas de nouveau thread d'exécution. De plus, l'appel de
la méthode run() d'une classe qui implémente l'interface Runnable ne crée pas de nouveau thread
d'exécution. Ce n'est que lorsque vous appelez la méthode start() qu'un nouveau thread d'exécution est
créé.

Nous avons deux façons de créer un thread en Java :


 Hériter de la classe Thread et redéfinir la méthode run().
 Construire une classe qui implémente l'interface Runnable et la méthode run(), puis créer un
objet de la classe Thread en transmettant l'objet Runnable en tant que paramètre, c'est l'approche
recommandée qui vous offre plus de flexibilité.

1.3.Création de threads en héritant de la classe Thread

Exercice d’application 1
1. Créer la classe Multithreading qui hérite de la classe Thread et qui affiche le thread en
cours d'exécution
Utiliser la syntaxe suivant Thread.currentThread ().getId ()
2. Dans la classe principale, tester avec n=4 le nombre des threads
Utiliser la méthode start()
Solution

44
class Multithreading extends Thread {
public void run() {
try {
// afficher le thread en cours d'exécution
System.out.println("Thread " + Thread.currentThread().getId() + " est en cours
d'exécution");

} catch (Exception e) {
System.out.println("Exception " + e.getMessage());
}
}
}
// classe principale
public class Multithread {
public static void main(String[] args) {
int n = 4; // nombre de threads
for (int i = 0; i < n; i++) {
Multithreading object = new Multithreading();
object.start();
}
}
}
Résultat :

Thread 11 est en cours d'exécution


Thread 17 est en cours d'exécution
Thread 16 est en cours d'exécution
Thread 13 est en cours d'exécution

1.4.Création de threads en implémentant l'interface Runnable

Exercice d’application 2
1- Créer la classe Multithreading qui implémente l’interface Runnable et qui affiche le
thread en cours d'exécution
Utiliser la syntaxe suivant Thread.currentThread ().getId ()
2- Dans la classe principale, tester avec n=4 le nombre des threads
Utiliser la méthode start()
Solution

45
class Multithreading implements Runnable {
public void run() {
try {
// afficher le thread en cours d'exécution
System.out.println("Thread " + Thread.currentThread().getId() + " est en cours d'exécution");

} catch (Exception e) {
System.out.println("Exception " + e.getMessage());
}
}
}
// classe principale
public class Multithread {
public static void main(String[] args) {
int n = 4; // nombre de threads Résultat :
for (int i = 0; i < n; i++) {
Thread objet = new Thread(new Multithreading()); Thread 16 est en cours d'exécution
objet.start(); Thread 15 est en cours d'exécution
}}} Thread 13 est en cours d'exécution
Thread 14 est en cours d'exécution
Note :

Classe de Thread vs interface Runnable[7] :

 Si nous étendons la classe Thread, notre classe ne pourra pas hériter d’une autre classe car Java
ne prend pas en charge l’héritage multiple. Toutefois, si nous implémentons l'interface Runnable,
notre classe peut toujours hériter de d'autres classes de base.
 Nous pouvons obtenir les fonctionnalités de base d'un thread en héritant de la classe Thread, car
elle fournit des méthodes intégrées telles que yield(), interrupt(), etc. qui ne sont pas
disponibles dans l'interface Runnable.

4. Synchronisation des threads en java


1.5.Principe de la synchronisation
Lorsque nous démarrons deux ou plusieurs threads dans un programme, il peut arriver que plusieurs
threads essaient d'accéder à la même ressource et qu'ils puissent finalement produire des résultats
imprévus en raison de problèmes de concurrence. Par exemple, si plusieurs threads essaient d'écrire dans
le même fichier, ils risquent de corrompre les données, car l'un des threads peut remplacer les données
ou lorsqu'un thread ouvre le même fichier en même temps qu'un autre peut fermer le même fichier.

Il est donc nécessaire de synchroniser l'action de plusieurs threads et de vous assurer qu'un seul thread
peut accéder à la ressource à un moment donné. Ceci est mis en œuvre en utilisant un concept
appelé moniteurs. Chaque objet en Java est associé à un moniteur, qu'un thread peut verrouiller ou
déverrouiller. Un seul thread à la fois peut verrouiller un moniteur.

46
Le langage de programmation Java offre un moyen très pratique de créer des threads et de synchroniser
leur tâche à l’aide de blocs synchronized. Vous conservez des ressources partagées dans ce bloc.

Syntaxe :
synchronized(objectidentifier) {
// Accéder aux variables partagées et autres ressources partagées
}

Ici Objectidentifier est une référence à un objet dont le verrou est associé au moniteur représenté par
l'instruction synchronized.

Voici un exemple simple qui peut ou non d'afficher la valeur du compteur en séquence et chaque fois
que nous l'exécutons, il produit un résultat différent en fonction de la disponibilité du processeur pour un
thread

Exemple 1
class Compteur {
public void afficher() {
try {
for (int i = 10; i >= 0; i--) {
System.out.println("i = " + i);
}
} catch (Exception e) {
System.out.println("Thread interrompu.");
}
}
}
class Multithreading implements Runnable {
Compteur cpt;
public Multithreading(Compteur cpt) {
this.cpt = cpt;
}
public void run() {
cpt.afficher();
System.out.println("Bye bye " + Thread.currentThread().getName());
}
}
Résultat
// classe principale
public class Multithread { i=4
public static void main(String[] args) { i=4
Compteur cpt = new Compteur(); i=3
Thread obj1 = new Thread(new Multithreading(cpt)); i=3
i=2
Thread obj2 = new Thread(new Multithreading(cpt));
i=2
obj1.start();
i=1
i=1
i=0
47 i=0
Bye bye Thread-1
Bye bye Thread-0
obj2.start();
// attendre la fin des threads
try {
obj1.join();
obj1.join();
} catch (Exception e) {
}
}}

Dans l'exemple 2 ci-dessous, nous avons choisi de synchroniser l'objet Compteur dans la
méthode run() de la classe Multithreading. Alternativement, nous pourrions définir l'ensemble du bloc
de la méthode afficher() comme étant synchronisé et produire le même résultat.

Exemple 2
class Compteur {
public void afficher() {
try {
for (int i = 4; i >= 0; i--) {
System.out.println("i = " + i);
}
} catch (Exception e) {
System.out.println("Thread interrompu.");
}
}
}
class Multithreading implements Runnable {
Compteur cpt;
public Multithreading(Compteur cpt) {
this.cpt = cpt;
}
public void run() {
synchronized (cpt) {
cpt.afficher();
}
System.out.println("Bye bye " + Thread.currentThread().getName());
}
Résultat
}
i=4
// classe principale i=3
public class Multithread { i=2
public static void main(String[] args) { i=1
Compteur cpt = new Compteur(); i=0
Thread obj1 = new Thread(new Multithreading(cpt)); i=4
i=3
i=2
i=1
48
i=0
Bye bye Thread-1
Bye bye Thread-0
Thread obj2 = new Thread(new Multithreading(cpt)); Not
obj1.start(); e :
obj2.start();
// attendre la fin des threads  L
try { orsq
obj1.join(); u'un
obj1.join(); thre
} catch (Exception e) { ad
} entr
} e
} dans
une
méthode ou un bloc synchronisé, il acquiert un verrou et une fois qu'il a terminé sa tâche et qu'il
quitte la méthode synchronisée, il libère le verrou.
 Lorsque le thread entre dans une méthode ou un bloc d'instance synchronisée, il acquiert un
verrou de niveau objet et lorsqu'il entre dans une méthode ou un bloc statique synchronisé, il
acquiert un verrou de niveau de classe.
 La synchronisation Java lève une exception NullPointerException si l'objet utilisé dans un bloc
synchronisé est nul. Par exemple, si dans synchronized (instance), instance est null, elle lève une
exception NullPointerException.
 En Java, wait(), notify() et notifyAll() sont les méthodes importantes utilisées dans la
synchronisation.
 Vous ne pouvez pas appliquer le mot clé java synchronized aux variables.
 Ne synchronisez pas sur le champ non final du bloc synchronisé, car la référence au champ non
final peut changer à tout moment et différents threads peuvent alors se synchroniser sur
différents objets, c’est-à-dire qu’il n’ya aucune synchronisation.

1.6.Avantages de la Synchronisation
 Multithreading: comme Java est un langage multithread, la synchronisation est un bon moyen de
parvenir à une exclusion mutuelle sur les ressources partagées.
 Méthodes d'instance et statiques: les méthodes d'instance synchronisées et les méthodes statiques
synchronisées peuvent être exécutées simultanément car elles sont utilisées pour verrouiller
différents objets.

1.7.Limites de la Synchronisation
 Limitations de la simultanéité: la synchronisation Java n'autorise pas les lectures simultanées.
 Diminution de l'efficacité: la méthode synchronized s'exécute très lentement et peut dégrader les
performances. Vous devez donc synchroniser la méthode lorsque cela est absolument nécessaire
et ne synchroniser le bloc que pour la section critique du code

49
Chapitre 6 Construction d’une interface graphique en java

Objectifs

 Connaitre les APIs Graphiques,


 Connaitre et comprendre les composants de la bibliothéque AWT et Swing,
 Savoir définir une interface graphique en utilisant les composants de la
bibliothèque Swing.

Une interface graphique assure le dialogue entre utilisateur et application. Elle est formée d’une ou
plusieurs fenêtres qui contiennent divers composants graphiques (Boutons, listes déroulantes,
Menus, champ texte, …etc.)

Les composants d'une interface utilisateurs sont placés dans des conteneurs selon un gestionnaire de
placement (layout) pour contrôler leurs dispositions.

50
1. Interface Graphique
1.1. Les APIs Graphiques
Plusieurs packages permettent de gérer les interfaces graphiques : AWT et SWING (intégré à partir
de la version 1.2) :

 AWT utilise des composants lourds, c'est à dire utilisant les ressources du système
d'exploitation, alors que Swing utilise des composants dits légers n'utilisant pas ces
ressources.
 Swing est plus robuste que l'AWT, plus portable, et plus facile à utiliser. Swing ne
remplace pas complètement AWT mais fournit des composants d'interface plus
performants et plus ergonomiques.

1.2. Application graphique


Une application graphique AWT est composée de 3 éléments[8]:

 Les composants graphiques élémentaires de l’application (Boutons, menu, Etiquettes, zones


de textes, zones de choix, …). Ils héritent tous de java.awt.component
 Le conteneur graphique global qui est une zone spatiale sur laquelle les composants sont
placés. Parmi les conteneurs distingue les Fenêtres, les Frames, les panneaux, …. Les
conteneurs héritent de java.awt.container
 Le gestionnaire de présentation, dit LayoutManager, qui fixe la politique de placement des
composants sur le conteneur. Parmi les gestionnaires, on distingue le FlowLayout,
BorderLayout, le GridLayout, …

1.3. Hiérarchie des classes de AWT

Organisation des classes dans AWT

51
2. Les Composants
Chaque type d'objet de l'interface graphique est une classe dérivée de Component. Une classe
component est formée par les méthodes suivantes [13][14]:

Exemple de composants :

Exemples de composants

Méthode Rôle
setVisible(boolean visible) affiche ou masque le composant
2.1. L
getSize() retourne la dimension actuelle du composant,
e
retourne le type Dimension qui est utilisable
s
ainsi : getSize().height et getSize().width
getPreferedSize() Retourne la taille "idéale" du composant,
é
retourne le type Dimension t
redimensionne le composant à la i
setSize(Dimension d) dimension q
indiquée u
setSize(int largeur, int hauteur) redimensionne le composant e
move(int coordX, int coordY) déplace le composant au point indiqué (coin t
haut et gauche) t
setEnabled(boolean actif) active ou non le composant, c'est à dire le rend e
sensible aux événements. s
setForeground(Color couleur) définit la couleur d'avant-plan (de dessin) du
composant (
setBackground(Color couleur) définit la couleur de fond
L
abel)

52
L’utilisation des étiquettes implique le passage par les étapes suivantes :

 Importer la classe java.awt.Label


 Utiliser l’un des constructeurs suivants:
o Label()
o Label (String arg) : Permet de préciser le libellé de l’étiquette.
o Label (String arg, int arg ) : permet de préciser respectivement le libellé et son alignement
(Static int LEFT=0, CENTER=1, RIGHT=2)
Exemple 1
Label l1 = new Label( );
l1.setText("une etiquette");
Exemple 2
Label l1 = new Label("une etiquette");
Exemple 3
Label l1 = new Label("etiquette", Label.CENTER);

2.2. Les boutons (Button)


L’utilisation des boutons implique le passage par les étapes suivantes :

 Importer la classe java.awt.Button


 Utiliser l’un des constructeurs suivants:
o Button()
o Button(String) : Permet de préciser le libellé du bouton
Exemple 1
Button b1 = new Button()
b1.setLabel("annuler")
Exemple 2
Button bouton = new Button("annuler")

2.3. Les champs de texte (TextField)


L’utilisation des champs de texte implique le passage par les étapes suivantes :

 Importer la classe java.awt.TextField


 Utiliser l’un des constructeurs suivants:
o TextField();
o TextField( int ); spécification du nombre de caractères saisir
o TextField( String ); avec texte par défaut
o TextField( String, int ); avec texte par défaut et nombre de caractères à saisir.

Exemple 1
TextField tf = new TextField(10)
Exemple 2

53
TextField tf = new TextField(“champ de texte”)
Exemple 3
TextField tf = new TextField(“champ de texte”,10)
Note :

On pourra utiliser les méthodes suivantes :

o String getText( ) : retourne la chaine saisie dans le champ de texte.


o int getColumns( ) : retourne nombre de caractères prédéfini

2.4. Les zones de texte (TextArea)


L’utilisation des zones de texte implique le passage par les étapes suivantes :

 Importer la classe java.awt.TextArea


 Constructeurs:
o TextArea()
o TextArea( int, int ) : avec spécification du nombre de lignes et de colonnes
o TextArea( String ) : avec texte par défaut
o TextArea( String, int, int ) : avec texte par défaut et taille
Exemple
TextArea ta = new TextArea(commentaire,10,10)

2.5. Liste déroulante ( choice)


 Importer la classe java.awt.Choice
 Constructeur : Choice();
 add() et addItem() permettent d'ajouter des éléments à la liste déroulante :
o c1.add("element 1");
o ou c1.addItem("element 2");
 Plusieurs méthodes permettent la gestion des sélections :
o void select( int ) : sélectionner un élément par son indice : le premier élément correspond
à l'indice 0.
o void select( String): sélectionner un élément par son contenu
o int getItemCount( ) : permet d'obtenir le nombre d'éléments de la combo
o String getItem( int ) : lire le contenu de l'élément d'indice n
o String getSelectedItem() : déterminer le contenu de l'élément sélectionné.

2.6. Case à cocher ( Checkbox)


Importer la classe java.awt.Checkbox.

Constructeurs :

o Checkbox( )
o Checkbox( String) : avec une étiquette
o Checkbox( String,boolean) : avec une étiquette et un état

54
o Checkbox(String,CheckboxGroup, boolean) : avec une étiquette, dans un groupe de
cases à cocher et un état
Méthodes :

o void setLabel(String) : modifier l'étiquette


o void setState( boolean ) : fixer l'état
o boolean getState( ) : consulter l'état de la case
o String getLabel( ) : lire l'étiquette de la case

Exercice d’application 1 :
Donner le morceau du code pour afficher une interface graphique comportant trois cases à
cocher (Utiliser le type FlowLayout)

Solution
import java.awt.*;
class Fcheck {
static public void main (String arg [ ]) {
Frame w = new Frame("Exemple de fenetre avec case à cocher"); w.setLayout(new FlowLayout ());
Checkbox box1=new Checkbox("un",false); w.add(box1);
Frame w = new Frame("Exemple de fenetre avec case à cocher"); w.setLayout(new FlowLayout ());
Checkbox box1=new Checkbox("un",false); w.add(box1);
Checkbox box2=new Checkbox("deux",true); w.add(box2);
Checkbox box3=new Checkbox("trois",false);
w.add(box3);
w.show();
w.pack();}}

2.7. Bouton radio (CheckboxGroup)


Importer la classe java.awt.CheckboxGroup.

Constructeurs :

o CheckboxGroup()

55
o Checkbox(String label, CheckboxGroup group, boolean state) // Crée un bouton radio intitulé
label et l'ajoute au groupe group, en l'activant si state est true.
Méthodes :

o getSelectedCheckbox(): Retourne l'objet Checkbox correspondant à la réponse sélectionnée


o setSelectedCheckbox(Checkbox) : Coche le bouton radio passé en paramètre

2.8. Les Menus


 Il faut créer une barre de menu (MenuBar) et l'affecter à la fenêtre d'encadrement (Frame).
 Il faut créer ensuite les entrées de chaque menu (Menu) et les rattacher à la barre (MenuBar).
 Ajouter ensuite les éléments (MenuItem) à chacun des menus.
 Les sous options de menu peuvent être séparées par un trait horizontal par ajout d'un MenuItem
spécial (newMenuItem ("-") ;) ou par les méthodes void addSeparator () ou void
insertSeparator (int index) de la classe java.awt.Menu.

Hiérarchie des menus

Exercice d’application 2 :
Donner le code necessaire à l’affichage de l’interface graphique ci-joint :

Solution

56
import java.awt.*; menu.add(item1);
public class Fmenu { menu.add(item2);
private MenuItem item1, item2, item4, menu.add(submenu);
item5; public Fmenu() { submenu.add(item4);
Frame frame = new Frame("Exemple de submenu.add(item5);
fenêtre avec menu"); MenuBar menuBar = menuBar.add(menu);
new MenuBar(); frame.setMenuBar(menuBar);
Menu menu = new Menu("File"); frame.pack();
Menu submenu = new Menu("Save"); frame.setVisible(true);
item1 = new MenuItem("New"); }
item2 = new MenuItem("Open"); public static void main(String[] args) { new Fmenu();}}
item4 = new MenuItem("c:");
item5 = new MenuItem("d:");

3. Les Conteneurs
Le conteneur Frame est le conteneur principal :

o Frame() crée une fenêtre sans titre


o Frame( String ) : spécification du titre de la fenêtre méthodes :
o setTitle(String titre) spécifie le titre
o setMenuBar(MenuBar) applique une barre de menu en haut du cadre
o setResizable(boolean) détermine si le cadre peut être redimensionné par l'utilisateur

3.1. Panneau (Panel)


Les panneaux sont des conteneurs qui permettent de rassembler des composants et de les positionner
grâce à un gestionnaire de présentation (FlowLayout par défaut).

Contructeurs :

o Panel() crée un Panel


o Panel(LayoutManager manager) crée un Panel avec le manager spécifique
3.2. Boite de dialogue (Dialog)
Les boîtes de dialogue s’appuient sur les frames pour disposer de leur propre fenêtre.

 S'appuyant sur un frame, une boîte de dialogue dispose de son propre layout
(java.awt.BorderLayout par défaut).
 Les constructeurs de la classe java.awt.Dialog:
o public Dialog (Frame parent, String title)
o public Dialog (Frame parent, String title, boolean modal)
Exemple

57
import java.awt.Dialog;
import java.awt.Frame;
class AppliWindow{
public static void main(String [ ] arg) { Frame fen = new Frame ("Bonjour" );
fen.setBounds(100,100,250,150);
Dialog fenetreDial = new Dialog (fen,"Informations"); fenetreDial.setSize(150,70);
fenetreDial.setVisible( true);
fen. setVisible ( true );}}
Resultat

4. Les gestionnaires de présentation


Gère la disposition des composants fils dans un conteneur

Hiérarchie des layouts

4.1. FlowLayout
FlowLayout : range de gauche à droite et de haut en bas.

o FlowLayout() range les composants en les centrant avec un "vspacing et


hspacing" (espace vertival, respectivement horizontal) de 5 pixels.
o FlowLayout(int aligne) range les composants en les alignant selon aligne :
FlowLayout.LEFT,

58
o FlowLayout.CENTER, FlowLayout.RIGHT avec un vspacing et hspacing de 5 pixels.
o FlowLayout(int aligne, int vspacing, int hspacing) range selon l'alignement et le
vspacing et le hspacing spécifiés.
Exercice d’application 3 :
Donner le code necessaire à l’affichage de l’interface graphique ci-joint :

Solution
import java.awt.*;
class Fflow {
static public void main (String arg [ ]) {
Frame w = new
w.setLayout(new FlowLayout ());
Button b1=new
w.add(b1);
Button b2=new Button("deux");
w.add(b2);
Button b3=new Button("trois");
w.add(b3);
w. show()
w.pack();}}

4.2. BorderLayout
Ce gestionnaire divise un composant container en 5 zones: North, East, South, West, Center

 BorderLayout() crée 5 zones


 BorderLayout(int hspacing, int vspacing) idem avec un espacement spécifié. la méthode add est
par exemple add("North", composant)
Exercice d’application 4 :
Donner le code necessaire à l’affichage de l’interface graphique ci-joint :

Solution

59
import java.awt.*; Button b3=new Button("Center");
class FBorder { w.add("Center",b3);
static public void main (String arg [ ]) { Button b4=new Button("West");
Frame w = new Frame("Exemple de w.add("West",b4);
fenetre avec Border layout"); Button b5=new Button("South");
w.setLayout(new BorderLayout ()); w.add("South",b5);
Button b1=new Button ("North"); w.show();
w.add("North",b1); w.pack();
Button b2=new Button("East"); }}
w.add("East",b2);

4.3. GridLayout
Ce gestionnaire range dans une grille/matrice de gauche à droite et de haut en bas

Constructeurs :

o GridLayout(int ligne, int colonne) Les deux premiers entiers spécifient le nombre de lignes et de
colonnes de la grille
o GridLayout(int ligne, int colonne, int hspacing, int vspacing) idem avec l’espacement vertical et
horizental spécifiés.
Exercice d’application 5 :
Donner le code necessaire à l’affichage de l’interface graphique ci-joint :

Solution

60
import java.awt.*;
class FGrid {
static public void main (String arg [ ]) {
Frame w = new Frame("Exemple de fenetre avec Grid layout"); w.setLayout(new
GridLayout(3, 3, 5, 5));
Button b1=new Button ("un");
w.add(b1);
Button b2=new Button("deux");
w.add(b2);
Button b3=new Button("trois");
w.add(b3);
Button b4=new Button("quatre");
w.add(b4);
Button b5=new Button("cinq");
w.add(b5);
Button b6=new Button("six");
w.add(b6);
w.show();
w.pack();}}

Chapitre 7Gestion des évènements

Objectifs

 Connaitre le principe d’interception des actions de l’utilisateur à savoir l’objet


source et l’objet écouteur,
 Définir les interfaces de base pour gérer les évènements,
 Connaitre et savoir utiliser les différentes implémentations des Listeners.

61
Une interface graphique doit interagir avec l'utilisateur et donc réagir à certains événements. On
distingue donc[8] :

 Objets sources d'événements : génèrent des événements en réponse à des actions de l’utilisateur
ex: fenêtre, bouton, panneau…
 Objets écouteurs d'événements s’inscrivent auprès d’objets source : Les écouteurs d'évènements
sont des interfaces regroupées par familles d'évènements et isolées dans java.awt.event. ex
ActionListener, MouseListener, MouseMotionListener, WindowListener,
Ce chapitre traite de la capture de ces événements pour leur associer des traitements.

1. L'interception des actions de l'utilisateur

Les événements utilisateurs sont gérés par plusieurs interfaces EventListener. Les interfaces
EventListener permettent de définir les traitements en réponse à des événements utilisateurs généré par
un composant. Une classe doit contenir une interface auditrice pour chaque type d'événements à traiter :

 ActionListener : clic de souris ou enfoncement de la touche Enter


 ItemListener : utilisation d'une liste ou d'une case à cocher
 MouseMotionListener : événement de souris
 WindowListener : événement de fenêtre

L'ajout d'une interface EventListener impose plusieurs ajouts dans le code :

 Importer le groupe de classes java.awt.event

import java.awt.event.*

 La classe doit déclarer qu'elle utilisera une ou plusieurs interfaces d'écoute

public class AppletAction extends Applet implements ActionListener{

 Pour déclarer plusieurs interfaces, il suffit de les séparer par des virgules

public class MonApplet extends Applet implements ActionListener, MouseListener {

 Appel à la méthode addXXX() pour enregistrer l'objet qui gérera les événements XXX du
composant

Il faut configurer le composant pour qu'il possède un «écouteur» pour l'événement utilisateur concerné.

Button b = new Button("boutton")


b.addActionListener(this)

62
Ce code crée l'objet de la classe Button et appelle sa méthode addActionListener(). Cette méthode
permet de préciser la classe qui va gérer l'événement utilisateur de type ActionListener du bouton.

Cette classe doit impérativement implémenter l'interface de type EventListener correspondante soit
dans cet exemple ActionListener. L'instruction this indique que la classe elle-même recevra et gérera
l'événement utilisateur[8] :

Note :

L'apparition d'un événement utilisateur généré par un composant doté d'un auditeur appelle
automatiquement une méthode. Cette dernière doit se trouver dans la classe référencée dans l'instruction
qui lie l'auditeur au composant.

Dans l'exemple, cette méthode doit être située dans la même classe parce que c'est l'objet lui-même qui
est spécifié avec l'instruction this. Une autre classe indépendante peut être utilisée : dans ce cas il faut
préciser une instance de cette classe en tant que paramètre[8] :

2. Implémenter les méthodes déclarées dans les interfaces

Chaque auditeur possède des méthodes différentes qui sont appelées pour traiter leurs événements. Par
exemple, l'interface ActionListener envoie des événements à une méthode nommée actionPerformed(
).

Syntaxe
public void actionPerformed(ActionEvent evt) {
//insérer ici le code de la méthode
};

Pour identifier le composant qui a généré l'événement, il faut utiliser la méthode getActionCommand()
de l'objet ActionEvent fourni en paramètre de la méthode :

Exemple
String composant = evt.getActionCommand() ;

La méthode getActionCommand() renvoie une chaîne de caractères. Si le composant est un bouton,


alors il renvoie le texte du bouton, si le composant est une zone de saisie, c'est le texte saisi qui sera
renvoyé (il faut appuyer sur «Entrer» pour générer l'événement), etc ...

La méthode getSource() renvoie l'objet qui a généré l'événement. Cette méthode est plus sûre que la
précédente.

Exemple

63
La
Button b = new Button(" bouton "); méthod
... e
void public actionPerformed(actionEvent evt) { getSou
Object source = evt.getSource(); rce()
if (source == b) // action à effectuer } peut
être
utilisée avec tous les événements utilisateur.

2.1.L'interface ItemListener

Cette interface permet de réagir à la sélection de cases à cocher et de listes d'options. Pour qu'un
composant génère des événements, il faut utiliser la méthode addItemListener().

Exemple
Checkbox cb = new Checkbox(" choix ",true) ;
cb.addItemListener(this) ;

Ces événements sont reçus par la méthode itemStateChanged() qui attend un objet de type ItemEvent
en argument.

Pour déterminer si une case à cocher est sélectionnée ou inactive, utiliser la méthode getStateChange()
avec les constantes ItemEvent.SELECTED ou ItemEvent.DESELECTED.

Exemple

64
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class AppletItem extends Applet implements ItemListener{
public void init() {
super.init();
Checkbox cb = new Checkbox("choix 1", true);
cb.addItemListener(this);
add(cb);
}
public void itemStateChanged(ItemEvent item) {
int status = item.getStateChange();
if (status == ItemEvent.SELECTED)
showStatus("choix selectionne");
else
showStatus("choix non selectionne");
}
}
Note :

 Pour connaitre l'objet qui a généré l'événement, il faut utiliser la méthode getItem().
 Pour déterminer la valeur sélectionnée dans une combo box, il faut utiliser la méthode getItem() et
convertir la valeur en chaîne de caractères.

Exemple
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class AppletItem extends Applet implements ItemListener{
public void init() {
Choice c = new Choice();
c.add("choix 1");
c.add("choix 2");
c.add("choix 3");
c.addItemListener(this);
add(c);
}
public void itemStateChanged(ItemEvent item) {
Object obj = item.getItem();
String selection = (String)obj;
showStatus("choix : "+selection);}}

65
2.2.L'interface TextListener

Cette interface permet de réagir aux modifications de la zone de saisie ou du texte. La méthode
addTextListener() permet à un composant de texte de générer des événements utilisateur. La méthode
TextValueChanged() reçoit les événements[8] :

Exemple
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class AppletText extends Applet implements TextListener{
public void init() {
super.init();
TextField t = new TextField("");
t.addTextListener(this);
add(t);
}
public void textValueChanged(TextEvent txt) {
Object source = txt.getSource();
showStatus("saisi = "+((TextField)source).getText());}}

2.3.L'interface MouseMotionListener

La méthode addMouseMotionListener() permet de gérer les événements liés à des mouvements de


souris. Les méthodes mouseDragged() et mouseMoved() reçoivent les événements.

Exemple
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class AppletMotion extends Applet implements MouseMotionListener{
private int x;
private int y;
public void init() {
super.init();
this.addMouseMotionListener(this);}
public void mouseDragged(java.awt.event.MouseEvent e) {}
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
showStatus("x = "+x+" ; y = "+y); }
public void paint(Graphics g) {
super.paint(g); g.drawString("x = "+x+" ; y = "+y,20,20); }}

66
2.4.L'interface MouseListener

Cette interface permet de réagir aux clics de souris. Les méthodes de cette interface sont :

 public void mouseClicked(MouseEvent e);


 public void mousePressed(MouseEvent e);
 public void mouseReleased(MouseEvent e);
 public void mouseEntered(MouseEvent e);
 public void mouseExited(MouseEvent e);

Exemple

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class AppletMouse extends Applet implements MouseListener {
int nbClick = 0;
public void init() {
super.init();
addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
nbClick++;
repaint();}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}

public void paint(Graphics g) {


super.paint(g);
g.drawString("Nombre de clics : "+nbClick,10,10); }}

Une classe qui implémente cette interface doit définir ces 5 méthodes. Si toutes les méthodes ne doivent
pas être utilisées, il est possible de définir une classe qui hérite de MouseAdapter. Cette classe fournit
une implémentation par défaut de l'interface MouseListener.

Exemple
class gestionClics extends MouseAdapter {
public void mousePressed(MouseEvent e) {
//traitement
}
}

67
Note :

 Dans le cas d'une classe qui hérite d'une classe Adapter, il suffit de redéfinir la ou les méthodes
qui contiendront du code pour traiter les événements concernés. Par défaut, les différentes
méthodes définies dans l'Adapter ne font rien.
 Cette nouvelle classe ainsi définie doit être passée en paramètre à la méthode
addMouseListener() au lieu de this qui indiquait que la classe répondait elle même à
l'événement.

2.5.L'interface WindowListener

La méthode addWindowListener() permet à un objet Frame de générer des événements. Les méthodes
de cette interface sont :

 public void windowOpened(WindowEvent e)


 public void windowClosing(WindowEvent e)
 public void windowClosed(WindowEvent e)
 public void windowIconified(WindowEvent e)
 public void windowDeinconified(WindowEvent e)
 public void windowActivated(WindowEvent e)
 public void windowDeactivated(WindowEvent e)

Note :

 windowClosing() est appelée lorsque l'on clique sur la case système de fermeture de la fenêtre.
 windowClosed() est appelé après la fermeture de la fenêtre : cette méthode n'est utile que si la
fermeture de la fenêtre n'entraine pas la fin de l'application.

Exemple

import java.awt.event.*;
class GestionnaireFenetre extends WindowAdpter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}

68
import java.awt.*;
import java.awt.event.*;
public class TestFrame extends Frame {
private GestionnaireFenetre gf = new GestionnaireFenetre();
public TestFrame(String title) {
super(title);
addWindowListener(gf);
}
public static void main(java.lang.String[] args) {
try {
TestFrame tf = new TestFrame("TestFrame");
tf.setVisible(true);
} catch (Throwable e) {
System.err.println("Erreur");
e.printStackTrace(System.out);
}
}
}

3. Les différentes implémentations des Listeners

La mise en oeuvre des Listeners peut se faire selon différentes formes : la classe implémentant elle
même l'interface, une classe indépendante, une classe interne, une classe interne anonyme.

3.1.Classe implémentant elle même le listener

Exemple
import java.awt.*;
import java.awt.event.*;
public class TestFrame3 extends Frame implements WindowListener {
public TestFrame3(String title) {
super(title);
this.addWindowListener(this);
}
public static void main(java.lang.String[] args) {
try {
TestFrame3 tf = new TestFrame3("testFrame3");
tf.setVisible(true);
} catch (Throwable e) {
System.err.println("Erreur");
e.printStackTrace(System.out);
}
}

69
Suite

public void windowActivated(java.awt.event.WindowEvent e) {}


public void windowClosed(java.awt.event.WindowEvent e) {}
public void windowClosing(java.awt.event.WindowEvent e) {
System.exit(0);
}
public void windowDeactivated(java.awt.event.WindowEvent e) {}
public void windowDeiconified(java.awt.event.WindowEvent e) {}
public void windowIconified(java.awt.event.WindowEvent e) {}
public void windowOpened(java.awt.event.WindowEvent e) {}
}

3.2. Une classe indépendante implémentant le listener

Exemple
import java.awt.*;
import java.awt.event.*;
public class TestFrame4 extends Frame {
public TestFrame4(String title) {
super(title);
gestEvt ge = new gestEvt();
addWindowListener(ge);
}
public static void main(java.lang.String[] args) {
try {
TestFrame4 tf = new TestFrame4("testFrame4");
tf.setVisible(true);
} catch (Throwable e) {
System.err.println("Erreur");
e.printStackTrace(System.out);
}
}
}

70
import java.awt.event.*;
public class gestEvt implements WindowListener {

public void windowActivated(WindowEvent e) {}


public void windowClosed(WindowEvent e) {}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
}

3.3. Une classe interne

import java.awt.*;
import java.awt.event.*;
public class TestFrame2 extends Frame {
class gestEvt implements WindowListener {
public void windowActivated(WindowEvent e) {};
public void windowClosed(WindowEvent e) {};
public void windowClosing(WindowEvent e) {
System.exit(0);
};
public void windowDeactivated(WindowEvent e) {};
public void windowDeiconified(WindowEvent e) {};
public void windowIconified(WindowEvent e) {};
public void windowOpened(WindowEvent e) {};
};
private gestEvt ge = new TestFrame2.gestEvt();
public TestFrame2(String title) {
super(title);
addWindowListener(ge); }

public static void main(java.lang.String[] args) {


try {
TestFrame2 tf = new TestFrame2("TestFrame2");
tf.setVisible(true);
} catch (Throwable e) {
System.err.println("Erreur");
e.printStackTrace(System.out);}}}

71
3.4. Une classe interne anonyme

import java.awt.*;
import java.awt.event.*;
public class TestFrame1 extends Frame {
public TestFrame1(String title) {
super(title);
addWindowListener(new WindowAdapter() {
public void windowClosed(.WindowEvent e) {
System.exit(0);
};
});
}
public static void main(java.lang.String[] args) {
try {
TestFrame1 tf = new TestFrame1("TestFrame");
tf.setVisible(true);
} catch (Throwable e) {
System.err.println("Erreur");
e.printStackTrace(System.out); }}}
Note :

 Associer au composant qui est à l'origine de l'événement un contrôleur adéquat : utilisation des
méthodes addXXXListener(). Le paramètre de ces méthodes indique l'objet qui a la charge de
répondre au message : cet objet doit implémenter l'interface XXXListener correspondante ou
dérivée d'une classe XXXAdapter, ce qui revient à créer une classe qui implémente l'interface
associée à l'événement que l'on veut gérer.
 Cette classe peut être celle du composant qui est à l'origine de l'événement (facilité
d'implémentation) ou une classe indépendante qui détermine la frontière entre l'interface
graphique (émission d'événements) et celle qui représente la logique de l'application (traitement
des événements) .
 Les classes XXXAdapter sont utiles pour créer des classes dédiées au traitement des événements
car elles implémentent des méthodes par défaut pour celles définies dans l'interface
XXXListener dérivées de EventListener. Il n'existe une classe Adapter que pour les interfaces
qui possèdent plusieurs méthodes.
 Implémenter la méthode associée à l'événement qui fournit en paramètre un objet de type
AWTEvent (classe mère de tout événement) contenant des informations utiles (position du
curseur, état du clavier ...)

72
Chapitre 8 JDBC (Java DataBase Connectivity)

Objectifs

 Connaitre les outils nécessaires pour utiliser le gérer une source des données
sous java,
 connaitre et savoir utiliser le package java.sql,
 Maitriser l’utilisation de la classe ResultSet et l’interface PreparedStatement.

JDBC est l'acronyme de Java DataBase Connectivity et désigne une API pour permettre un accès aux
bases de données avec Java.

1. Les outils nécessaires pour utiliser JDBC

Les classes de JDBC version 1.0 sont regroupées dans le package java.sql et sont incluses dans le JDK à
partir de sa version 1.1. La version 2.0 de cette API est incluse dans la version 1.2 du JDK.

Pour pouvoir utiliser JDBC, il faut un pilote qui est spécifique à la base de données à laquelle on veut
accéder. Avec le JDK, Sun fournit un pilote qui permet l'accès aux bases de données via ODBC.Ce
pilote permet de réaliser l'indépendance de JDBC vis à vis des bases de données [11].

1.1.Les types de pilotes JDBC

Il existe quatre types de pilote JDBC :

1. Type 1 ( JDBC-ODBC bridge ) : le pont JDBC-ODBC qui s'utilise avec ODBC et un pilote
ODBC spécifique pour la base à accéder. Cette solution fonctionne très bien sous Windows.
C'est une solution pour des développements avec exécution sous Windows d'une application
locale qui a le mérite d'être universelle car il existe des pilotes ODBC pour la quasi totalité des
bases de données. Cette solution "simple" pour le développement possède plusieurs
inconvénients [12]:

o la multiplication du nombre de couches rend complexe l'architecture (bien que


transparent pour le développeur) et détériore un peu les performances
o lors du déploiement, ODBC et son pilote doivent être installés sur tous les postes où
l'application va fonctionner
o la partie native (ODBC et son pilote) rend l'application moins portable et dépendante
d'une plate-forme
2. Type 2 : un driver écrit en Java qui appelle l'API native de la base de données

73
Ce type de driver convertit les ordres JDBC pour appeler directement les API de la base de
données via un pilote natif sur le client. Ce type de driver nécessite aussi l'utilisation de code
natif sur le client.

3. Type 3 : un driver écrit en Java utilisant un middleware

Ce type de driver utilise un protocole réseau propriétaire spécifique à une base de données. Un
serveur dédié reçoit les messages par ce protocole et dialogue directement avec la base de
données. Ce type de driver peut être facilement utilisé par une applet mais dans ce cas le serveur
intermédiaire doit obligatoirement être installé sur la machine contenant le serveur web.

4. Type 4 : un driver Java utilisant le protocole natif de la base de données

Ce type de driver, écrit en java, appelle directement le SGBD par le réseau. Il est fourni par
l'éditeur de la base de données.

Les drivers se présentent souvent sous forme de fichiers jar dont le chemin doit être ajouté au classpath
pour permettre au programme de l'utiliser.

1.2.Le choix du pilote JDBC à utiliser

La qualité du pilote JDBC est importante notamment en termes de rapidité, type de pilote, version de
JDBC supportée, ...

Le type du pilote influe grandement sur les performances :

 Le type 1 (pont JDBC/ODBC) : les pilotes de ce type sont à éviter car les différentes couches
mises en oeuvre (JDBC, pilote JDBC, ODBC, pilote ODBC, base de données) dégradent les
performances
 Le type 2 (utilise une API native) : les pilotes de ce type ont généralement des performances
moyennes
 Le type 3 (JDBC, pilote JDBC, middleware, DB) : les pilotes de type 3 communiquent avec un
middleware généralement sur le serveur. Ils sont le plus souvent plus performants que ceux de
type 1 et 2
 Le type 4 (JDBC, pilote JDBC, DB) les pilotes de type 4 offre en général les meilleures
performances car ils sont écrits en Java et communiquent directement avec la base de données

Note :

 Il est donc préférable d'utiliser des pilotes de type 4 ou 3.


 Il peut être intéressant de tester le pilote proposé par le fournisseur de la base de données mais
aussi de tester des pilotes fournis par des tiers.
 Il est préférable d'utiliser un pilote qui supporte la version la plus récente de JDBC.

1.3.La présentation des classes de l'API JDBC

74
Toutes les classes de JDBC sont dans le package java.sql. Il faut donc l'importer dans tous les
programmes devant utiliser JDBC.

Syntaxe
import java.sql.*

Il y a 4 classes importantes : DriverManager, Connection, Statement (et PreparedStatement), et


ResultSet, chacune correspondant à une étape de l'accès aux données :

Classe Rôle
DriverManager Charger et configurer le driver de la base de données.
Connection Réaliser la connexion et l'authentification à la base de
données.
Statement (et PreparedStatement) Contenir la requête SQL et la transmettre à la base de
données.
ResultSet Parcourir les informations retournées par la base de données
dans le cas d'une sélection de données

Chacune de ces classes dépend de l'instanciation d'un objet de la précédente classe.

2. La connexion à une base de données

La connexion à une base de données requiert au préalable le chargement du pilote JDBC qui sera utilisé
pour communiquer avec la base de données. Une fabrique permet alors de créer une instance de type
Connection qui va encapsuler la connection à la base de données.

2.1. Le chargement du pilote

Pour se connecter à une base de données via ODBC, il faut tout d'abord charger le pilote JDBC-ODBC
qui fait le lien entre les deux.

Exemple
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;

Connecter à une base en utilisant un driver spécifique, la documentation du driver fournit le nom de la
classe à utiliser. Par exemple, si le nom de la classe est jdbc.DriverXXX, le chargement du driver se fera
avec le code suivant :

Class.forName("jdbc.DriverXXX")

Exemple : Chargement du pilote pour un base PostgreSQL sous Linux


Class.forName("postgresql.Driver") ;

75
Il n'est pas nécessaire de créer une instance de cette classe et de l'enregistrer avec le DriverManager car
l'appel à Class.forName le fait automatiquement : ce traitement charge le pilote et crée une instance de
cette classe.

La méthode static forName() de la classe Class peut lever l'exception


java.lang.ClassNotFoundException.

2.2. L'établissement de la connexion

Pour se connecter à une base de données, il faut instancier un objet de la classe Connection en lui
précisant sous forme d'URL la base à accéder [9][10] :

Exemple ( code Java 1.1 ) : Etablir une connexion sur la base testDB via ODBC
String DBurl = "jdbc:odbc:testDB"
con = DriverManager.getConnection(DBurl) ;

Note :

 La syntaxe URL peut varier d'un type de base de données à l'autre mais elle est toujours de la
forme : protocole:sous_protocole:nom
 "jbdc" désigne le protocole et vaut toujours "jdbc". "odbc" désigne le sous protocole qui définit
le mécanisme de connexion pour un type de base de données.
 Le nom de la base de données doit être celui saisi dans le nom de la source sous ODBC.
 La méthode getConnection() peut lever une exception de la classe java.sql.SQLException.

Exemple : Le code suivant décrit la création d'une connexion avec un user et un mot de passe :
Connection con = DriverManager.getConnection(url, "myLogin", "myPassword") ;

A la place de " myLogin " ; il faut mettre le nom du user qui se connecte à la base et mettre son mot de
passe à la place de "myPassword " :

Exemple
String url = "jdbc:odbc:factures"
Connection con = DriverManager.getConnection(url, "toto", "passwd") ;

Connection à la base PostgreSQL nommée test avec le user jumbo et le mot de passe 12345 sur la
machine locale

Exemple : Connection à la base PostgreSQL nommée test avec le user jumbo et le mot de passe 12345
sur la machine locale
Connection con=DriverManager.getConnection("jdbc:postgresql://localhost/test","jumbo","12345") ;

76
3. L'accès à la base de données

Une fois la connexion établie, il est possible d'exécuter des ordres SQL. Les objets qui peuvent être
utilisés pour obtenir des informations sur la base de données sont :

Classe Rôle
DatabaseMetaData informations à propos de la base de données : nom des tables, index, version ...
ResultSet résultat d'une requête et information sur une table. L'accès se fait enregistrement
par enregistrement.
ResultSetMetaData informations sur les colonnes (nom et type) d'un ResultSet

3.1.L'exécution de requêtes SQL

Les requêtes d'interrogation SQL sont exécutées avec les méthodes d'un objet Statement que l'on obtient
à partir d'un objet Connection

Exemple
ResultSet résultats = null;
String requete = "SELECT * FROM client";
try {
Statement stmt = con.createStatement();
résultats = stmt.executeQuery(requete);
} catch (SQLException e) {
//traitement de l'exception
}

Un objet de la classe Statement permet d'envoyer des requêtes SQL à la base. La création d'un objet
Statement s'effectue à partir d'une instance de la classe Connection :

Exemple
Statement stmt = con.createStatement()

Pour une requête de type interrogation (SELECT), la méthode à utiliser de la classe Statement est
executeQuery(). Pour des traitements de mise à jour, il faut utiliser la méthode executeUpdate(). Lors de
l'appel à la méthode d'exécution, il est nécessaire de lui fournir en paramètre la requête SQL sous forme
de chaine.

Le résultat d'une requête d'interrogation est renvoyé dans un objet de la classe ResultSet par la méthode
executeQuery().

Exemple
ResultSet rs = stmt.executeQuery("SELECT * FROM employe") ;

La méthode executeUpdate() retourne le nombre d'enregistrements qui ont été mis à jour

77
Exemple
...
//insertion d'un enregistrement dans la table client
requete = "INSERT INTO client VALUES (3,'client 3','prenom 3')";
try {
Statement stmt = con.createStatement();
int nbMaj = stmt.executeUpdate(requete);
affiche("nb mise a jour = "+nbMaj);
} catch (SQLException e) {
e.printStackTrace();
}
...

Lorsque la méthode executeUpdate() est utilisée pour exécuter un traitement de type DDL ( Data
Definition Langage : définition de données ) comme la création d'un table, elle retourne 0. Si la méthode
retourne 0, cela peut signifier deux choses : le traitement de mise à jour n'a affecté aucun enregistrement
ou le traitement concernait un traitement de type DDL[12].

Si l'on utilise executeQuery() pour exécuter une requête SQL ne contenant pas d'ordre SELECT, alors
une exception de type SQLException est levée.

Exemple
…requete = "INSERT INTO client VALUES (4,'client 4','prenom 4')";
try {
Statement stmt = con.createStatement();
ResultSet résultats = stmt.executeQuery(requete);
} catch (SQLException e) {
e.printStackTrace(); Résultat
} java.sql.SQLException: No ResultSet was produced
... java.lang.Throwable(java.lang.String)
java.lang.Exception(java.lang.String)
java.sql.SQLException(java.lang.String)
java.sql.ResultSet
sun.jdbc.odbc.JdbcOdbcStatement.executeQuery(java.lang.String)
void testjdbc.TestJDBC1.main(java.lang.String [])
Note :

 Dans ce cas la requête est quand même effectuée. Dans l'exemple, un nouvel enregistrement est
créé dans la table
 Il n'est pas nécessaire de définir un objet Statement pour chaque ordre SQL : il est possible d'un
définir un et de le réutiliser

3.2.La classe ResultSet

78
C'est une classe qui représente une abstraction d'une table qui se compose de plusieurs enregistrements
constitués de colonnes qui contiennent les données.Les principales méthodes pour obtenir des données
sont :

Méthode Rôle
getInt(int) retourne sous forme d'entier le contenu de la colonne dont le numéro est passé en
paramètre.
getInt(String) retourne sous forme d'entier le contenu de la colonne dont le nom est passé en
paramètre.
getFloat(int) retourne sous forme d'un nombre flottant le contenu de la colonne dont le numéro est
passé en paramètre.
getFloat(String) retourne sous forme d'un nombre flottant le contenu de la colonne dont le nom est
passé en paramètre.
getDate(int) retourne sous forme de date le contenu de la colonne dont le numéro est passé en
paramètre.
getDate(String) retourne sous forme de date le contenu de la colonne dont le nom est passé en
paramètre.
next() se déplace sur le prochain enregistrement : retourne false si la fin est atteinte
close() ferme le ResultSet
getMetaData() retourne un objet de type ResultSetMetaData associé au ResultSet.

La méthode getMetaData() retourne un objet de la classe ResultSetMetaData qui permet d'obtenir des
informations sur le résultat de la requête. Ainsi, le nombre de colonnes peut être obtenu grâce à la
méthode getColumnCount() de cet objet[11].

Exemple
ResultSetMetaData rsmd ;
rsmd = results.getMetaData() ;
nbCols = rsmd.getColumnCount() ;
Note :

 La méthode next() déplace le curseur sur le prochain enregistrement. Le curseur pointe


initialement juste avant le premier enregistrement : il est nécessaire de faire un premier appel à la
méthode next() pour se placer sur le premier enregistrement.
 Des appels successifs à next permettent de parcourir l'ensemble des enregistrements.
 Elle retourne false lorsqu'il n'y a plus d'enregistrement. Il faut toujours protéger le parcours d'une
table dans un bloc de capture d'exception

Exemple

79
//parcours des données retournées
try {
ResultSetMetaData rsmd = resultats.getMetaData();
int nbCols = rsmd.getColumnCount();
while (resultats.next()) {
for (int i = 1; i <= nbCols; i++)
System.out.print(resultats.getString(i) + " ");
System.out.println(); }
resultats.close();
} catch (SQLException e) {
//traitement de l'exception
}

Les méthodes getXXX() permettent d'extraire les données selon leur type spécifié par XXX tel que
getString(), getDouble(), getInteger(), etc ... . Il existe deux formes de ces méthodes : indiquer le numéro
de la colonne en paramètre (en commençant par 1) ou indiquer le nom de la colonne en paramètre. La
première méthode est plus efficace mais peut générer plus d'erreurs à l'exécution notamment si la
structure de la table évolue[10]

Note :

 Il est important de noter que ce numéro de colonne fourni en paramètre fait référence au numéro
de colonne de l'objet resultSet (celui correspondant dans l'ordre SELECT) et non au numéro de
colonne de la table.
 La méthode getString() permet d'obtenir la valeur d'un champ de n'importe quel type.

3.3. Un exemple complet de mise à jour et de sélection sur une table

Voici un exemple qui traite et explique un exemple de mise à jour et de sélection sur une table de base
de données[9] :

import java.sql.*;
public class TestJDBC1 {
private static void affiche(String message) {
System.out.println(message);
}
private static void arret(String message) {
System.err.println(message);
System.exit(99);
}
public static void main(java.lang.String[] args) {
Connection con = null;
ResultSet résultats = null;
String requete = "";
// chargement du pilote

80
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException e) {
arret("Impossible de charger le pilote jdbc:odbc");
}
//connection a la base de données
affiche("connexion a la base de données");
try {
String DBurl = "jdbc:odbc:testDB";
con = DriverManager.getConnection(DBurl);
} catch (SQLException e) {
arret("Connection à la base de données impossible");
}
//insertion d'un enregistrement dans la table client
affiche("creation enregistrement");
requete = "INSERT INTO client VALUES (3,'client 3','prenom 3')";
try {
Statement stmt = con.createStatement();
int nbMaj = stmt.executeUpdate(requete);
affiche("nb mise a jour = "+nbMaj);
} catch (SQLException e) {
e.printStackTrace();
}
//creation et execution de la requete
affiche("creation et execution de la requête");
requete = "SELECT * FROM client";
try {
Statement stmt = con.createStatement();
résultats = stmt.executeQuery(requete);
} catch (SQLException e) {
arret("Anomalie lors de l'execution de la requête");
}
//parcours des données retournées
affiche("parcours des données retournées");
try {
ResultSetMetaData rsmd = résultats.getMetaData();
int nbCols = rsmd.getColumnCount();
boolean encore = résultats.next();
while (encore) {
for (int i = 1; i <= nbCols; i++)
System.out.print(résultats.getString(i) + " ");
System.out.println();
encore = résultats.next();
} Résultat

connexion a la base de données


creation enregistrement
81 a jour = 1
nb mise
creation et execution de la requête
parcours des données retournées
1.0 client 1 prenom 1
2.0 client 2 prenom 2
résultats.close();
} catch (SQLException e) {
arret(e.getMessage());
}
affiche("fin du programme");
System.exit(0);
}
}

4. L'utilisation d'un objet de type PreparedStatement

L'interface PreparedStatement définit les méthodes pour un objet qui va encapsuler une requête
précompilée. Ce type de requête est particulièrement adapté pour une exécution répétée d'une même
requête avec des paramètres différents [13]:

 Cette interface hérite de l'interface Statement.


 Lors de l'utilisation d'un objet de type PreparedStatement, la requête est envoyée au moteur de la
base de données pour que celui-ci prépare son exécution.
 Un objet qui implémente l'interface PreparedStatement est obtenu en utilisant la méthode
preparedStatement() d'un objet de type Connection. Cette méthode attend en paramètre une
chaîne de caractères contenant la requête SQL. Dans cette chaîne, chaque paramètre est
représenté par un caractère ?[14].
 Un ensemble de méthode setXXX() (ou XXX représente un type primitif ou certains objets tels
que String, Date, Object, ...) permet de fournir les valeurs de chaque paramètre défini dans la
requête. Le premier paramètre de ces méthodes précises le numéro du paramètre dont la méthode
va fournir la valeur. Le second paramètre précise cette valeur.

Pour exécuter la requête, l'interface PreparedStatement propose deux méthodes :

 executeQuery() : cette méthode permet d'exécuter une requête de type interrogation et renvoie
un objet de type ResultSet qui contient les données issues de l'exécution de la requête
 executeUpdate() : cette méthode permet d'exécuter une requête de type mise à jour et renvoie un
entier qui contient le nombre d'occurrences impactées par la mise à jour

82
import java.sql.*;
public class TestJDBC2 {
private static void affiche(String message) {
System.out.println(message);
}
private static void arret(String message) {
System.err.println(message);
System.exit(99);
}
public static void main(java.lang.String[] args) {
Connection con = null;
ResultSet resultats = null;
String requete = "";
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException e) {
arret("Impossible de charger le pilote jdbc:odbc");
}
affiche("connexion a la base de données");
try {
String DBurl = "jdbc:odbc:testDB";
con = DriverManager.getConnection(DBurl);
PreparedStatement recherchePersonne =
con.prepareStatement("SELECT * FROM personnes WHERE nom_personne = ?");
recherchePersonne.setString(1, "nom3");
resultats = recherchePersonne.executeQuery();
affiche("parcours des données retournées");
boolean encore = resultats.next();
while (encore) {
System.out.print(resultats.getInt(1) + " : "+resultats.getString(2)+" "+
resultats.getString(3)+"("+resultats.getDate(4)+")");
System.out.println();
encore = resultats.next();
}
resultats.close();
} catch (SQLException e) {
arret(e.getMessage());
}
affiche("fin du programme");
System.exit(0);
}
}

83
5. Le traitement des erreurs JDBC

JDBC permet de connaitre les avertissements et les exceptions générées par la base de données lors de
l'exécution de requête. [14]

La classe SQLException représente les erreurs émises par la base de données. Elle contient trois
attributs qui permettent de préciser l'erreur :

 message : contient une description de l'erreur


 SQLState : code défini par les normes X/Open et SQL99
 ErrorCode : le code d'erreur du fournisseur du pilote

La classe SQLException possède une méthode getNextException() qui permet d'obtenir les autres
exceptions levées durant la requête. La méthode renvoie null une fois la dernière exception renvoyée.

Note :

Plusieurs best practices sont communément mises en oeuvre lors de l'utilisation de JDBC :

 Fermer les ressources inutilisées dès que possible (Connection, Statement, ResultSet)
 Ne retourner que les données utiles lors de l'utilisation de requêtes SQL
 Toujours assurer un traitement des warnings et des exceptions

import java.sql.*;
public class TestJDBC3 {
private static void affiche(String message) {
System.out.println(message);
}
private static void arret(String message) {
System.err.println(message);
System.exit(99);
}
public static void main(java.lang.String[] args) {
Connection con = null;
ResultSet resultats = null;
String requete = "";
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException e) {
arret("Impossible de charger le pilote jdbc:odbc");
}
affiche("connexion a la base de données");

84
try {
String DBurl = "jdbc:odbc:testDB";
con = DriverManager.getConnection(DBurl);
requete = "SELECT * FROM tableinexistante";
Statement stmt = con.createStatement();
resultats = stmt.executeQuery(requete);
affiche("parcours des données retournées");
boolean encore = resultats.next();
while (encore) {
System.out.print(resultats.getInt(1) + " : " + resultats.getString(2) +
" " + resultats.getString(3) + "(" + resultats.getDate(4) + ")");
System.out.println();
encore = resultats.next();
}
resultats.close();
} catch (SQLException e) {
System.out.println("SQLException");
do {
System.out.println("SQLState : " + e.getSQLState());
System.out.println("Description : " + e.getMessage());
System.out.println("code erreur : " + e.getErrorCode());
System.out.println("");
e = e.getNextException();
} while (e != null);
arret("");
} catch (Exception e) {
e.printStackTrace();
}
affiche("fin du programme");
System.exit(0); }}

Chapitre 9 JavaFX

Objectifs

 Connaitre les outils nécessaires pour utiliser la plateforme JavaFX,


85
 Connaitre l’architecture technique et les modules de JavaFX,
 Savoir comment se présente une application JavaFX
Java FX est un Framework et une bibliothèque d'interface utilisateur issue du projet OpenJFX, qui
permet aux développeurs Java de créer une interface graphique pour des applications de bureau,
des applications internet riches et des applications Smartphones et tablettes tactiles.

Créé à l'origine par Sun Microsystems, puis développé par Oracle après son rachat et ce, jusqu'à la
version 11 du JDK, c'est depuis lors à la communauté OpenJFX que revient la poursuite de son
développement1.

Cette bibliothèque a été conçue pour remplacer Swing et AWT, qui ont été développés à partir de la fin
des années 90, pour pallier les défauts de ces derniers et fournir de nouvelles fonctionnalités (dont le
support des écrans tactiles)[15].

1. Architecture technique et module de JavaFX


1.1. Architecture technique

L’Architecture technique de la plateforme JavaFX est composée de plusieurs couches (library stack) qui
reposent sur la machine virtuelle Java (JVM)

Applications JavaFX

Public Layer
Private Layer

Native Layer

86
 Les développeurs ne devrait utiliser que la couche (API) publique car les couches inférieures
sont susceptibles de subir des changements importants au fil des versions (sans aucune garantie
de compatibilité)
 Les "briques" intermédiaires ne seront donc pas décrites dans ce cours.

1.2.Module de JavaFX
Java FX est composé des 7 modules suivants:

 javafx.base: Définit l'API de base


 javafx.controls: Définit la majorité des composants graphiques de l'API
 javafx.fxml: Définit l'API relative au langage FXML qui permet de décrire une interface
utilisateur d'une manière alternative à l'écriture de lignes de code
 javafx.graphics: Définit l'API relative aux conteneurs, animations, effets visuels, formes 2D et
3D, images, impression,
 fenêtres, événements, robots, au support du CSS et à l'application
 javafx.media: Définit l'API dédié à la lecture de contenu audio et vidéo
 javafx.swing: Définit l'API qui fournit le support d’interopérabilité entre Java FX et Swing
 javafx.web: Définit l'API dédié à l'affichage de contenu web (notamment un éditeur HTML et un
moteur de rendu de pages web basé sur WebKi[15].

2. Les caractéristiques Java FX

Java FX qui fait partie de Java 8 constitue pour remplacer Swing Une caractéristique de Java FX est
d'être intégralement open source, ce qui n'est pas entièrement le cas de ses principaux concurrents
directs. Elle travaille sur plusieurs autres modules de la plate-forme Java FX notamment Java FX
Mobile et Java FX TV. Elle caractérisé par :

 Un grand choix de composants


 Des composants web
 Les moteurs graphiques et media (son, vidéo, images)
 Possède l'infrastructure pour faire les animations
 Java 3D inclus
 Permet aux développeurs d'intégrer des graphiques vectoriels, des animations, du son et des
vidéos récupérés sur Internet dans une application riche, dense et interactive.
 Etend la technologie Java grâce à l'utilisation de n'importe quelle bibliothèque Java au sein
d'une application Java FX.
 Améliore l'efficacité du travail entre concepteurs et développeurs, les premiers pouvant
utiliser les outils de leur choix tout en collaborant avec les seconds.

3. Comment se présente une application JavaFX ?

87
L'application est codée en créant une sous-classe d’Application

 La fenêtre principale d'une application est représentée par un objet de type stage qui est fourni par le
système au lancement de l'application.
 L'interface est représentée par un objet de type scene qu’il faut créer et associer à la fenetre (Stage)
 La méthode start()construit le tout.

Avec :

 Scène est un outil interactif de conception d'interface graphique pour JavaFX. Il permet de
créer des interfaces utilisateurs rapidement et sans avoir besoin de coder: il en résulte des fichiers
au format FXML qui sont ensuite chargés par le programme pour afficher une interface
graphique à ses utilisateurs.
 Stage est littéralement la scène d'une salle de théâtre, une estrade ou encore la piste d'un cirque : il s'agit
de l'endroit physique dans lequel votre application va s'afficher. La classe javafx.stage.Stage hérite de la
classe javafx.stage.Window[15].

Exemple: Une première application, le traditionnel Hello World !

public class Bienvenue extends Application {


@Override
public void start(Stage premierStage) {
premierStage.setTitle("My First JavaFX App");
BorderPane root = new BorderPane();
Button btnHello = new Button("Hello World");
root.setCenter(btnHello);
Scene scene = new Scene(root, 250, 100);
premierStage.setScene(scene);
premierStage.show();}
//---------------------------------------------
public static void main(String[] args) {
launch(args); }}

88
Dans cet exemple, la méthode main() lance uniquement la method statique launch() qui est héritée de
Application).

Dans une application un peu plus complexe, elle pourrait effectuer d'autres opérations d'initialisation avant
l'invoquer launch().

Note :

 JavaFX étant intégré à la plateforme de base Java, aucune librairie externe n'est nécessaire au
fonctionnement de l'exemple précédent.
 Un certain nombre d'importations doivent ce pendant être effectuées (on y retrouve les classes
principales Application, Stage, Scene ainsi que les composants BorderPane et Button ) .

import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.scene.layout.BorderPane
import javafx.stage.Stage

4. Cycle de vie d'une application JavaFX

Le point d'entrée d'une application JavaFX est constitué de l'instance de la classe Application
(généralement une sous-classe). Lors du lancement d'une application par la méthode statique
Application.launch() le runtime JavaFX effectue les opérations :

1. Crée une instance de la classe qui hérite de Application


2. Appelle la méthode init()
3. Appelle la méthode start()et lui passe en paramètre une instance de Stage (qui représente la
fenêtre principale [primary stage])
4. Attend ensuite que l'application se termine; cela se produit lorsque :
 La dernière fenêtre de l'application a été fermée (et
Platform.isImplicitExit()retourne true)
 L'application appelle Platform.exit() (ne pas utiliser System.Exit())
5. Appelle la method stop()
Note :

 La méthode launch() est généralement lancée depuis la méthode main(). Elle est implicitement
lancée s'il n'y a pas de méthode main() (ce qui est toléré depuis Java 8)

 Des paramètres de lancement peuvent être récupérés en invoquant la méthode getParameters()


dans la method init() ou ultérieurement.

 Invoquer ensuite getRaw()ou get … pour obtenir la liste (List<String>)

89
 La méthode start() est abstraite et doit être redéfinie.
 Les méthodes init() et stop() ne doivent pas obligatoirement être redéfinies (par défaut elle ne
font rien)
 La méthode start() s'exécute dans le JavaFX Application Thread.
C'est dans ce thread que doit être construite l'interface et que doivent être exécutées toutes les
opérations qui agissent sur des composants attachés à une scène (live components).

5. Traiter une action de l'utilisateur


Dans l'exemple Hello World, pour que le clic sur le bouton déclenche une action, il faut traiter
l'événement associé.

La method setOnAction() du bouton permet d'enregistrer un Event Handler (c'est une interface
fonctionnelle possédant la méthode handle(event) qui définit l'action à effectuer).

public void start(Stage premierStage) {


premierStage.setTitle("My First JavaFX App");
BorderPane root = new BorderPane();
Button btnHello = new Button("Say Hello");
btnHello.setOnAction(
event -> System.out.println("Hello World !"));
root.setCenter(btnHello);
Scene scene = new Scene(root, 250, 100);
premierStage.setScene(scene);
premierStage.show();}

90
Bibliographie

[1] Tutoriaux de formation de programmation en java


https://openclassrooms.com/fr/courses/26832-apprenez-a-programmer-en-java/22404-
apprehendez-la-genericite-en-java
[2] Cours Java
https://perso.telecom-paristech.fr/hudry/coursJava/exercices/index.html
[3] Documentation java-l’API Collection
https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html
[4] Les flux de base en java
https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html
https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html
[5] Cours les entrées-sorties en java
https://www.jmdoudoux.fr/java/dej/chap-nio2.htm
[6] Article sur l’utilisation des classes path et files en java
https://developpement-informatique.com/article/264/utilisation-des-classes-path-et-files-en-java
[7] Les Threads en java
ttps://download.java.net/java/early_access/loom/docs/api/java.base/java/lang/Thread.html
https://www.jmdoudoux.fr/java/dej/chap-threads.htm
[8] Cours Interface graphique en java
https://www.jmdoudoux.fr/java/dej/chap-swing.htm#swing
[9] La page de Sun du JDBC
http://java.sun.com/products/jdbc/
[10] Le didacticiel de Sun sur JDBC
http://java.sun.com/docs/books/tutorial/jdbc/
[11] La documentation du package java.sql
http://java.sun.com/j2se/1.4/docs/api/java/sql/package-summary.html
[12] Liste des pilotes JDBC de Sun
http://industry.java.sun.com/products/jdbc/drivers/
[13] Documentation JavaSE-version 8
https://docs.oracle.com/javase/8/docs/api/
[14] Documentation JavaSE-version 7
https://docs.oracle.com/javase/7/docs/api/
[15] Tutorial de formation JavaFX
https://code.makery.ch/fr/library/javafx-tutorial/

91

Vous aimerez peut-être aussi