Vous êtes sur la page 1sur 123

Cours de JAVA

Serge Rosmorduc rosmord@iut.univ-paris8.fr 20002005

TABLE DES MATIRES

Table des matires


I Le langage JAVA. Complments
1 Spcicateurs 1.1 Le mot clef final . . . . . . . . . . . . . 1.2 Le mot cl static . . . . . . . . . . . . . . . 1.2.1 Champs statiques . . . . . . . . . . 1.2.2 Mthodes statiques . . . . . . . . . 1.3 Accs aux champs et mthodes dune classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
3 3 4 4 6 6 9 9 9 9 10 10 10 10 11 11 12 12

Hritage 2.1 Rednition de fonctions . . . . . . . . . . . 2.2 Implmentation de lhritage . . . . . . . . . 2.3 Type et classes : le polymorphisme . . . . . . 2.4 Classes abstraites . . . . . . . . . . . . . . . 2.5 super et this . . . . . . . . . . . . . . . . 2.5.1 Introduction . . . . . . . . . . . . . . 2.5.2 Dnitions . . . . . . . . . . . . . . 2.5.3 super et this pour qualier des champs 2.5.4 super et this dans les mthodes . . . . 2.5.5 super et this dans les constructeurs . . 2.5.6 this comme argument de mthode . .

Interfaces 13 3.1 Les Interfaces comme spcication . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.2 Les interfaces comme collections de constantes . . . . . . . . . . . . . . . . . . 13 Cast 15 4.1 Cast et types de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4.2 Cast et classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Lidentit des objets 5.1 Comparaison dobjets : equals() . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Le hashcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Duplication dun objet : clone() . . . . . . . . . . . . . . . . . . . . . . . . . 17 17 18 18

ii 6 Exceptions 6.1 Introduction . . . . . . . . . . . . 6.2 Terminologie . . . . . . . . . . . 6.3 Les exceptions en JAVA . . . . . . 6.4 Propagation dexceptions . . . . . 6.5 Interception des exceptions en Java 6.5.1 La clause try...catch . . . . 6.5.2 La clause nally . . . . . 6.5.3 catch et lhritage . . . . . 6.6 Dnition dun type dexceptions

TABLE DES MATIRES


21 21 22 23 23 23 23 23 23 23 25 25 25 26 27 27 28 28 29 30 31 31 32 33 33 33 33 34 35 36 38 39 41

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Threads 7.1 Introduction . . . . . . . . . . . . . . . . . . . . 7.2 Dclaration . . . . . . . . . . . . . . . . . . . . 7.3 Lancement dun thread . . . . . . . . . . . . . . 7.4 Le partage du temps . . . . . . . . . . . . . . . . 7.4.1 Priorits . . . . . . . . . . . . . . . . . . 7.4.2 La mthode yield() . . . . . . . . . . 7.5 Variables partages . . . . . . . . . . . . . . . . 7.5.1 Synchronized . . . . . . . . . . . . . . . 7.5.2 Volatile . . . . . . . . . . . . . . . . . . 7.6 Contrle de lexcution . . . . . . . . . . . . . . 7.6.1 Arrt dun thread . . . . . . . . . . . . . 7.6.2 Attente de la n dun thread . . . . . . . 7.6.3 Mthode sleep . . . . . . . . . . . . . . 7.7 viter les attentes actives avec wait et notify 7.7.1 Introduction . . . . . . . . . . . . . . . . 7.7.2 Mthodes . . . . . . . . . . . . . . . . . 7.7.3 Utilisation de wait et notify . . . . . . . . 7.7.4 Client et serveur sans attente active . . . 7.7.5 Gestion dune le de messages . . . . . . 7.8 Dmons . . . . . . . . . . . . . . . . . . . . . . 7.9 Graphismes . . . . . . . . . . . . . . . . . . . . 7.9.1 synchronisation et graphismes . . . . . .

II Bibliothques particulires
1 Les Collections 1.1 Introduction . . . . . . . 1.2 Itrateurs . . . . . . . . 1.3 Organisation des classes 1.4 Linterface Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43
45 45 46 47 49

TABLE DES MATIRES


1.5 1.6 1.7 1.8 1.9 Listes . . . . . . . . . . . . . . . . . . . . . . . Ensembles . . . . . . . . . . . . . . . . . . . . . 1.6.1 Ensembles tris . . . . . . . . . . . . . . Dictionnaires (maps) . . . . . . . . . . . . . . . Piles (Stack) . . . . . . . . . . . . . . . . . . . Exemples . . . . . . . . . . . . . . . . . . . . . 1.9.1 La collection Sac . . . . . . . . . . . . . 1.9.2 Utilisation de Map pour compter des mots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

iii 50 51 51 52 53 53 53 54 57 57 60 60 60 60 61 62 62 63 63 65 65 66 66 67 67 68 68 68 68 68 70 75 75 75 75 76 76 77 77 78 78

Entres/sorties 2.1 La classe File . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Organisation des classes dentres/sortie . . . . . . . . . . . 2.2.1 Fichiers en lecture, chiers en criture . . . . . . . . 2.2.2 Classes orientes octets, classes orientes caractres 2.2.3 Filtrage . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Quelques Classes . . . . . . . . . . . . . . . . . . . . . . . 2.4 Exemples dutilisation . . . . . . . . . . . . . . . . . . . . 2.4.1 Lecture dun chier . . . . . . . . . . . . . . . . . . 2.5 Mthodes . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 Constructeurs . . . . . . . . . . . . . . . . . . . . . 2.5.2 Reader . . . . . . . . . . . . . . . . . . . . . . . . 2.5.3 Writer . . . . . . . . . . . . . . . . . . . . . . . . . 2.6 La classe RandomAccessFile . . . . . . . . . . . . . . . . . 2.6.1 Ouverture et fermeture . . . . . . . . . . . . . . . . 2.6.2 Lecture et criture . . . . . . . . . . . . . . . . . . 2.6.3 Dplacement . . . . . . . . . . . . . . . . . . . . . 2.7 Srialisation . . . . . . . . . . . . . . . . . . . . . . . . . . 2.7.1 Conditions demploi . . . . . . . . . . . . . . . . . 2.7.2 Champs non sauvegards . . . . . . . . . . . . . . . 2.8 La classe StreamTokenizer . . . . . . . . . . . . . . . . . . 2.8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . 2.8.2 Documentation . . . . . . . . . . . . . . . . . . . . Java et les bases de donnes 3.1 Introduction JDBC . . . . . . . . . . . . . 3.2 Architecture . . . . . . . . . . . . . . . . . . 3.3 Un exemple : postgres . . . . . . . . . . . . . 3.4 tablir la connexion . . . . . . . . . . . . . . 3.4.1 Exemple : . . . . . . . . . . . . . . . 3.5 Envoyer une requte . . . . . . . . . . . . . 3.5.1 Mthodes . . . . . . . . . . . . . . . 3.5.2 Mthodes applicables un ResultSet 3.5.3 Execute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

iv 3.6 3.7 3.8 Commandes prpares . . . . . . . . . . . . . . . . . . chappements SQL . . . . . . . . . . . . . . . . . . . . Gestion des transactions . . . . . . . . . . . . . . . . . 3.8.1 Niveau disolement . . . . . . . . . . . . . . . . 3.9 Capacits de la base de donnes : DataBaseMetaData 3.10 Exploration des tables . . . . . . . . . . . . . . . . . . . 3.10.1 mthodes de ResultSetMetaData . . . . . . 3.11 Extensions du jdbc2.0 . . . . . . . . . . . . . . . . . . . 3.11.1 ResultSet navigables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

TABLE DES MATIRES


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 79 80 80 81 81 82 82 82 85 85 85 85 86 87 87 87 87 87 89 90 90 91 93 94 94 94 96 96 96 96 96 97 97 97 97 101 103 103 103 107

Java Server Pages et Servlets 4.1 Architecture dune application web . . . . 4.2 Introduction aux jsp . . . . . . . . . . . . 4.2.1 principes . . . . . . . . . . . . . 4.2.2 Balises principales des jsp . . . . 4.2.3 Les champs dune jsp . . . . . . . 4.2.4 Installation des jsp . . . . . . . . 4.3 Introduction aux servlets . . . . . . . . . 4.3.1 principe des servlets . . . . . . . 4.3.2 Installation des servlets . . . . . . 4.3.3 Les servlets, leur vie, leur uvre . 4.4 Les javabeans . . . . . . . . . . . . . . . 4.4.1 Les classes de beans . . . . . . . 4.4.2 Accs aux beans depuis les jsp . . 4.4.3 accs aux beans depuis les servlets 4.5 Architecture typique dune application jsp 4.5.1 Redirection vers une jsp . . . . . 4.6 Le suivi des sessions . . . . . . . . . . . 4.7 Cration de nouvelles balises pour les jsp 4.7.1 Une balise simple . . . . . . . . . 4.7.2 Une boucle . . . . . . . . . . . . 4.7.3 Partage de variables . . . . . . . 4.8 Quelques patterns . . . . . . . . . . . . .

Java et XML 5.1 Le langage XML . . . . . . . . . . . . . . 5.1.1 Introduction . . . . . . . . . . . . . 5.1.2 Documents XML . . . . . . . . . . 5.1.3 XSLT . . . . . . . . . . . . . . . . 5.1.4 Schmas XML . . . . . . . . . . . 5.2 Les API Java . . . . . . . . . . . . . . . . 5.2.1 Document object model (DOM) . . 5.2.2 Simple API for Xml Parsing (SAX)

TABLE DES MATIRES


5.3 5.4 5.5 6 XSL et java . . . . . . . . . . . . . . . . . . . . . . . . . Quelques outils java utilisant XML . . . . . . . . . . . . . 5.4.1 SVG et Batik . . . . . . . . . . . . . . . . . . . . Appendice : un fragment de la description du langage XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

v 110 111 111 111 113 113 113 115 115 115

Swing Avanc 6.1 Patterns en swing : lexemple de JTable . . . . . . . . 6.1.1 Le pattern Observateur . . . . . . . . . . . . . . 6.2 Le pattern commande en swing : actions et edits . . . . . 6.2.1 Actions et le pattern commande . . . . . . . . . 6.2.2 Undo, classes textes et design pattern commande

vi

TABLE DES MATIRES

Premire partie Le langage JAVA. Complments

Chapitre 1 Spcicateurs
Un certain nombre de mots clefs permettent de spcier le comportement dun champ ou dune mthode. Nous dtaillerons ici final, static, ainsi que les oprateurs de visibilit public, private, protected.

1.1

Le mot clef final

Le mot clef nal se place dans la dclaration dun champ, dune classe ou dune mthode.Il indique que llment dclar ne peut tre modi. Dans le cas dun champ, il permet donc de dnir des constantes. On lutilise gnralement avec static (voir 1.2). Exemple :
class Cercle { private double x,y,r; static final double PI= 3.14; ... public double getPerimetre() { return 2*PI*r; } }

Il est aussi possible de lutiliser si la valeur dun champ est xe pour un objet donn. Par exemple, un objet de classe String nest pas modiable. Une dnition possible de cette classe serait donc :
public class MyString { private final char rep[]; public MyString(char t[]) { // Initialisation de rep rep= new char[t.length]; for (int i= 0; i< t.length; i++) rep[i]= t[i]; }

4
... }

CHAPITRE 1. SPCIFICATEURS

Notez que le nal de lexemple prcdent ninterdit pas de changer la valeur dune des cases du tableau rep. Il interdit uniquement faire pointer rep sur un autre tableau. Ainsi, le code suivant ne compilera pas :
public class MyString { ... public void set(char t[]) { rep= t; // Erreur la compilation : // "Cant assign a second value to a blank final variable: rep" } }

Dans le cas dune mthode, final interdit la rednition de la mthode par hritage. Dans le cas dune classe il interdit den driver des sous-classes.

1.2

Le mot cl static

Le mot-cl static vient du C. Il caractrise dans ce langage des variables dont la caractristique la plus marquante est de nexister quen un seul exemplaire. En JAVA, le mot-cl static indique quun lment dune classe est li la classe et non un objet particulier.

1.2.1 Champs statiques


Normalement, un champ dans une classe est li un objet. Par exemple, soit la classe Etudiant :
public class Etudiant { String nom; int numro; ... public Etudiant(String n) {nom= n;} public void setNumero(int n) {numero= n;} }

Le numro dun objet tudiant est li cet objet. Si nous considrons deux objets tudiants diffrents, e1 et e2, leurs numros seront deux donnes distinctes :
e1= new Etudiant("Turing"); e1.setNumero(0); e2= new Etudiant("Babbage"); e2.setNumero(1);

1.2. LE MOT CL STATIC


F IG . 1.1 Champs dans des objets dune mme classe

e1
nom numero 0 Turing

e2

nom numero 1

Babbage

lespace mmoire correspondant e1 et celui correspondant e2 contiennent chacun une place pour le numro et une place pour le nom, comme le montre la gure 1.1. Dans le cas de champs statiques, lespace mmoire pour le champ est rserv indpendamment des objets (gure 1.2). Il existe donc mme si aucun objet de la classe nexiste ; de plus il existe en un seul exemplaire. On y accde en crivant
NomDeLaCLASSE.nomDuChamp

Utilisation dun champ statique : Un champ statique sert gnralement pour conserver des caractristiques de la classe toute entire. Il sagit souvent de constantes (champs final static). Il peut cependant sagir de vritables variables. Par exemple, supposons que nous crivions dune classe Etudiant (au hasard) et que nous voulions que le numro dtudiant soit automatiquement incrment chaque nouvel tudiant cr. Nous pourrions crire :
public class Etudiant { static int maxnum= 0; int numero; String nom; ... public Etudiant(String nom) { numero= maxnum; maxnum= maxnum+1; this.nom= nom; } }

Remarquons cependant quil serait bien meilleur de crer une classe pour grer les numros dtudiants.

6 F IG . 1.2 Champs statiques dune classe

CHAPITRE 1. SPCIFICATEURS

e1
nom numero 0 Turing

e2

nom numero 1

Babbage nom et numero ne sont pas statiques maxnum est par contre un champ statique.

Etudiant
maxnum 2

1.2.2 Mthodes statiques


Une mthode statique est elle aussi indpendante des objets. Elle fonctionne donc comme les fonctions des langages non orients objets comme C. On les appelle en crivant :
NomDeLaCLASSE.nomDeLaFonction(Arguments)

Dans les bibliothques mathmatiques de Java, les fonctions usuelles sont dclares statiques ; en effet, elles ne sappliquent pas un objet :
x= Math.cos(1.4);

Lorsquun programme Java est lanc, il nexiste a priori aucun objet, donc aucun lment auquel appliquer une mthode. Cest pour cela que les concepteurs du langage ont dcid que le corps dun programme serait constitu par une mthode statique : main.

1.3

Accs aux champs et mthodes dune classe

public le champ est accessible de partout ; en pratique, rservez ce statut aux mthodes. La seule exception raisonnable pour les champs, ce sont les constantes. private le champ nest accessible que depuis la classe elle-mme. Si vous navez pas une excellente raison de donner un autre statut un champ ou une mthode, choisissez private.

1.3. ACCS AUX CHAMPS ET MTHODES DUNE CLASSE

(rien) le champ est accessible depuis toutes les classes du package ; a nest pas une raison pour en abuser :-). En pratique, il arrive parfois que plusieurs classes soient intimement lies. Typiquement, elles nont pas de sens les unes sans les autres. Dans ce cas, ce type daccessibilit est envisageable (voir par exemple 1.9.1 pour un usage possible). protected un champ protected dune classe A nest accessible que depuis le package et les classes drives de A. Typiquement, la classe A dnit une fonctions ou des champs qui seront utiles aux classes drives, et seulement celles-ci.

CHAPITRE 1. SPCIFICATEURS

Chapitre 2 Hritage
Lhritage est un mcanisme qui permet dtendre une classe en lui ajoutant des possibilits ou en rednissant certaines des fonctionnalits existantes. Concrtement, tant donn une classe A, lhritage permet de crer une classe B, qui a toutes les caractristiques de la classe A, plus ventuellement de nouveaux champs et de nouvelles mthodes.

2.1 2.2 2.3

Rednition de fonctions Implmentation de lhritage Type et classes : le polymorphisme

Introduisons quelques dnitions 1 : type un objet a un type et un seul : celui qui lui est donn par son constructeur. classe un objet peut par contre avoir plusieurs classes : celle correspondant son type, ainsi que toutes les sur-classes de celle-ci. Supposons que la classe Etudiant hrite de Personne qui hrite de Object. Alors :
Personne e= new Etudiant("toto");

cre un objet de type Etudiant, qui appartient aux classes Etudiant, Personne et Object. Par contre e est de classe Personne, ce qui est lgal car cest bien une des classes de lobjet. rednition (overriding) cest le fait de rcrire dans une classe B une mthode dune des classes dont B hrite. Lorsque cette mthode sera appele sur un objet de type B, alors cest la mthode rednie qui sera utilise et non la mthode de la classe anctre.
1. Lusage des mots type et classe dans ce sens nest notre connaissance pas standard. Cette terminologie provient du livre Design Patterns.

10

CHAPITRE 2. HRITAGE

surcharge (overloading) ne pas confondre avec le prcdent. cest le fait dutiliser le mme nom pour des mthodes diffrentes. Quand les mthodes sont dans la mme classe, elles sont distingues par leurs arguments. Notez que la surcharge na aucun rapport avec lhritage 2 . polymorphisme

2.4 2.5

Classes abstraites super et this

2.5.1 Introduction
En Java, il arrive parfois quune variable en cache une autre. Trs classiquement, considrons une classe Etudiant et un de ses constructeurs possibles :
public class Etudiant { String nom; public Etudiant(String nom) { ??? } }

Dans le corps du constructeur, le paramtre nom cache le champ (ou variable dinstance) nom . Dans 99 % des langages de programmation, le problme est rsolu en changeant le nom du paramtre. Cest l quintervient this. this signie lobjet auquel sapplique la mthode , ou, dans le cas dun constructeur, lobjet en train dtre construit . Dans ce cas, lcriture this.nom nest pas ambigu, et dsigne bien le champ nom de lobjet de classe Etudiant que nous construisons . Cette fonction, pour tre trs utilise en Java, nen est pas moins secondaire : on pourrait fort bien sen passer. Il est par contre des fois o lemploi de this ou de son compre super est primordial.

2.5.2 Dnitions
this signie lobjet auquel sapplique la mthode , ou, dans le cas dun constructeur, lobjet en train dtre construit ; super Semploie dans le cas dune classe B qui tend une classe de base A. Il signie lobjet auquel sapplique la mthode , ou, dans le cas dun constructeur, lobjet en train dtre construit , mais vu comme un objet de classe A.
2. La surcharge en java est un concept simple. En C++, nous verrons quelle est bien plus complexe, mais aussi plus puissante

2.5. SUPER ET THIS

11

2.5.3 super et this pour qualier des champs


this : quand un champ dun objet est cach par une variable locale ou un argument, le mot clef this permet de lever lambigut et de dsigner le champ. Classiquement :
public class Etudiant { String nom; public Etudiant(String nom) { this.nom= nom; // this.nom : champ nom de this // nom : argument du constructeur. } }

super : si une classe lle dnit un champ dont un homonyme existe dans une classe parente, ce dernier est masqu. Soit par exemple le code :
class A { public int a; } class B extends A { public String a; ... }

le champ a de type String de B masque le champ int de A. Le mot-clef super permet de faire rfrence, dans une mthode de la classe B, un objet de classe B en le considrant comme un objet de la classe parente, cest--dire A. Ainsi :
class B extends A { String a; ... public void afficher() { System.out.println(a); // affiche le champ String a System.out.println(super.a); // affiche le champ int a // hrit de A. } }

Notez que cet utilisation de super est trs rare. En effet, il est formellement dconseill daccder directement aux champs dune classe. Normalement, on aurait d crire des accesseurs.

2.5.4 super et this dans les mthodes


this : il est licite dcrire
this.appelDeMethode();

12 mais comme cest quivalent


appelDeMethode();

CHAPITRE 2. HRITAGE

cest parfaitement inutile. super : lide est toujours la mme. Supposons que nous ayons :
class Personne { ... public void afficher() { // affiche les donnes relative une personne : // son nom, son prnom, son adresse. ... } } class Etudiant extends Personne { ... public void afficher() { // affiche les donnes relative un tudiant : // dabord les donnes existantes dans la classe Personne, // puis celles spcifiques aux tudiants. } }

Il serait intressant de pouvoir utiliser la mthode afficher de Personne pour crire celle de Etudiant.

2.5.5 super et this dans les constructeurs 2.5.6 this comme argument de mthode

13

Chapitre 3 Interfaces
3.1 Les Interfaces comme spcication

Le mcanisme de lhritage en Java est limit lhritage simple. Une classe a une parente directe et une seule (sauf Object, qui nen a pas du tout). Lhritage a un sens trs fort : B hrite de A signie tout B est un A . Or, il arrive que lon veuille simplement signier quune classe sait faire telle ou telle chose. Cest le sens des interfaces. Une interface est principalement un ensemble den-ttes de mthodes. Une classe peut implmenter une ou plusieurs interfaces, cest dire fournir le code correspondant aux mthodes de linterface.

3.2

Les interfaces comme collections de constantes

Les interfaces peuvent aussi contenir des constantes. Il suft alors dimplmenter linterface pour pouvoir les utiliser. Considrons par exemple linterface suivante :
public interface CodesJours { int DIMANCHE= 0; int LUNDI= 1; int MARDI= 2; int MERCREDI= 3; int JEUDI= 4; int VENDREDI= 5; int SAMEDI= 6; }

Notez que ces champs sont en ralit static et final, mais quil est optionnel de lcrire. Toute classe qui implmente CodesJours dispose directement des constantes quelle dnit :
class Calendrier implements CodesJours { ... initWeekEnd() {

14
// Notez que SAMEDI est utilis directement jour[SAMEDI].setRepos(true); jour[DIMANCHE].setRepos(true); } ... }

CHAPITRE 3. INTERFACES

15

Chapitre 4 Cast
Lopration de conversion (casting) couvre en Java deux concepts diffrents. Elle se comporte en effet diffremment sur les types de base, o il sagit dune vritable conversion, et sur les classes, o cest plutt une opration syntaxique.

4.1

Cast et types de base

Les divers types de base (int, double, etc...) sont plus ou moins compatibles entre eux. On conoit par exemple quil soit logique de pouvoir crire un entier dans un double. Java permet dailleurs cette opration sans autre forme de procs :
int i= 1; double y= i;

Par contre, certaines conversions causent une perte dinformation. crire un double dans un int, cest en perdre la partie dcimale. De mme, crire un int dans un short (entier court) peut conduire une perte de donnes. En Java, les conversions avec perte de donne potentielle sont possibles, mais, contrairement aux conversions sans perte de donnes, elles doivent tre explicitement marque par lopration de casting. Un cast permet de convertir une donne dun type de base en un autre. Il scrit en faisant prcder la valeur convertir par le nom du type cible de la conversion, crit entre parenthses :
double y= 1.3; int j= (double)y;

4.2

Cast et classes

Pour reprendre le vocabulaire de 2.3,

16

CHAPITRE 4. CAST

17

Chapitre 5 Lidentit des objets


Le problme de lidentit est simple premire vue : il sagit de savoir si deux objets sont les mmes . Nanmoins, les apparences sont trompeuses. Par dfaut pour java chaque objet cr est diffrent des autres.

5.1

Comparaison dobjets : equals()

La mthode equals est hrite par toutes les classes. La classe Objet dnit equals comme :
public boolean equals(Objet o) { return this == o; }

Cest donc initialement un quivalent de ==. Pour les classes qui veulent disposer dune dnition diffrente de lgalit, on doit rednir equals. Cest ce que fait, par exemple, la classe String. Exemple de rednition :
class Entier { int val; Encapsulation dun entier

public Entier(int v) {val= v;} public // // if { boolean equals(Object o) { On compare un Entier et un Object. Ils peuvent tre de type diffrent : (o instanceof Entier) // o est un Entier. Le rcuprer comme tel // grce un cast : Entier e= (Entier)o; return (e.val == val);

18

CHAPITRE 5. LIDENTIT DES OBJETS


} else // o nest pas un Entier. Donc il ne peut tre gal this return false; } // Fonction hashCode. Voir ci-dessous. public int hashCode() { return val; } public int getValeur() {return val;} public void setValeur(int v) {val= v;}

5.2

Le hashcode

Si une classe rednit equals, elle doit aussi rednir la mthode hashcode : public int hashcode () fonction renvoyant un entier, utilise par les classes comme Hashtable, HashMap et HashSet. La contrainte est que si deux objets sont gaux au sens de equals, ils doivent avoir le mme hashcode (la rciproque ntant pas forcment vrie : deux objets peuvent avoir le mme code, mais tre diffrents). Par contre, plus le hashcode diffrencie des objets diffrents, plus il est efcace. Notez quune fonction constante remplit les conditions (mais ne fournit pas un bon hashcode. Si hashcode et equals sont en dsaccord, les classes telles que HashTable, qui utilisent le hashcode, donneront des rsultats errons.

5.3

Duplication dun objet : clone()

rdiger
public class Etudiant implements Cloneable { private String nom; protected Object Clone() { try { Etudiant e = (Etudiant)super.clone(); e.nom = (String)nom.clone(); return e;

5.3. DUPLICATION DUN OBJET : CLONE()


} catch (CloneNotSupportedException e) { // Impossible } } }

19

Important clone() ne peut ni utiliser un constructeur de la classe cloner, ni appeler new pour construire son rsultat.

20

CHAPITRE 5. LIDENTIT DES OBJETS

21

Chapitre 6 Exceptions
BON EXEMPLE POUR LES EXCEPTIONS : la classe Note.

6.1

Introduction

Dans de nombreux langages de programmations, comme C, la gestion derreurs est un domaine dlicat et, disons-le, rebutant. Cest sans doute la raison pour laquelle de nombreux programmeurs la ngligent, ce qui peut aboutir des problmes graves. Ainsi, par exemple, la plupart des failles de scurits dans les systmes UNIX sont causes par lexploitation dune gestion derreur dfectueuse. Pourquoi la gestion derreur pose-t-elle des problmes? Considrons lexemple suivant : soit un programme qui ouvre un chier, y lit trois entiers, puis le ferme. Lalgorithme est donc le suivant :
f= ouvrir_fichier(nom); i1= lire_entier(f); i2= lire_entier(f); i3= lire_entier(f); fermer f;

La lecture de ce code ne pose aucun problme, et lon voit tout de suite ce quil fait. Malheureusement, chaque tape, un problme peut se poser : le chier peut ne pas exister ou ne pas tre consultable. Dautre part, il peut contenir des donnes errones, et la lecture de i1, i2 et i3 peut chouer. Regardons quoi correspondrait un systme grant les erreurs :
si ((f= ouvrir_fichier(nom)) == 0) affiche "fichier non ouvert" exit 1 i1= lire_entier(f); si erreur_de_lecture affiche "fichier non ouvert" exit 1 i2= lire_entier(f); si erreur_de_lecture

22
affiche "fichier non ouvert" exit 1 i3= lire_entier(f); si erreur_de_lecture affiche "fichier non ouvert" exit 1 fermer f;

CHAPITRE 6. EXCEPTIONS

On saperoit que ce code est plus lourd, et bien moins lisible que le code prcdent. Le mcanisme des exceptions permet de sparer le code qui dcrit le droulement normal du programme et le code de gestion derreur. Cest ce que fait linstruction try ... catch :
try code dcrivant le droulement normal du programme catch type derreur 1 traitement de lerreur 1 catch type derreur 2 traitement de lerreur 2

Ainsi, notre lecture de chier scrirait :


try f= ouvrir_fichier(nom); i1= lire_entier(f); i2= lire_entier(f); i3= lire_entier(f); fermer f; catch fichier non ouvert afficher fichier non ouvert catch entier non lu fermer f; afficher fichier mal form

Le principe est le suivant : ouvrir_fichier ou lire_entier, si elles chouent, lvent une exception, cest dire envoient un message derreur. Cela interrompt le programme en cours. Par exemple, si la lecture de i1 choue, les lignes suivantes ne seront pas excutes. Au lieu de cela, le contrle passe aux blocs catch qui suivent le try, et le code correspondant lexception leve (dans notre exemple, entier non lu) est excut. Propagation : rien noblige, de plus, grer une erreur dans la fonction mme o elle se produit. Si une exception nest pas traite dans la mthode o elle est leve, elle se propage, en remontant le l des appels de mthodes. En n de compte, si elle nest jamais traite, elle interrompt lexcution du programme.

6.2

Terminologie

Exception : objet reprsentant un message derreur ; Leve dune exception : envoi dun message derreur, qui interrompt le cours normal du programme ;

6.3. LES EXCEPTIONS EN JAVA

23

Propagation dune exception : mcanisme par lequel une exception est transmise de fonction en fonction ; Traitement dune exception : interruption de lexception, permettant ventuellement de reprendre le cours du programme.

6.3

Les exceptions en JAVA

Certaines mthodes peuvent dclencher des exceptions. La documentation de lAPI java lindique alors :
public static int parseInt(String s) throws NumberFormatException

un appel de parseInt peut lever une exception si la valeur de s nest pas correcte Le programmeur qui appelle une telle mthode doit prciser sil intercepte lexception ou la laisse se propager.

6.4

Propagation dexceptions

Quand un programmeur appelle une mthode qui peut dclencher une exception, et quil dcide de ne pas intercepter celle-ci, il doit le prciser. Si, dans une mthode, mettons lireFichier(), on appelle la mthode parseInt voque prcdemment, il est

6.5

Interception des exceptions en Java

6.5.1 La clause try...catch 6.5.2 La clause nally 6.5.3 catch et lhritage

6.6

Dnition dun type dexceptions

* exceptions : try... catch, throws, throw - organisation des exceptions By convention, class Throwable and its subclasses have two constructors, one that takes no arguments and one that takes a String argument that can be used to produce an error message. try int a[] = new int[2]; a[4]; catch (ArrayIndexOutOfBoundsException e) System.out.println("exception: " + e.getMessage()); e.printStackTrace(); Error : non rattrapables

24

CHAPITRE 6. EXCEPTIONS

Exception : The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch. RuntimeException : Ces exceptions nont pas forcment besoin dtre rattrapes. Error LinkageError NoClassDefFoundError Exception IOException EOFException FileNotFoundException RuntimeException ArithmeticException NumberFormatException IndexOutOfBoundsException ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException NullPointerException - liste de catch - nally

25

Chapitre 7 Threads
7.1 Introduction

Dnition : Si plusieurs parties dun programme sexcutent en mme temps (ou semblent sexcuter en mme temps), on dit quelles sexcutent en parallle. Chaque excution de partie de programme est appele un thread (ou l dexcution). Les threads permettent donc dcrire des programmes multitches. Par dfaut, un programme Java est compos dun seul Thread. la diffrence des processus dUnix, les threads dun mme programme partagent le mme espace mmoire, et communiquent facilement entre eux.

7.2

Dclaration

Il existe deux mthodes pour excuter des threads. Une premire mthode est dtendre la classe Thread. Dans ce cas, il faut rednir la mthode run. Au lancement du thread, cest cette mthode qui sera excute.
// Thread hritant de la classe thread : public class T1 extends Thread { volatile private T2 k; public void setK(T2 k) { this.k= k; } // Ce thread affiche de manire rpte la valeur de // la variable k public void run() { while (true) { System.out.println(k); try {

26
// Attend une milliseconde sleep(1); } catch (InterruptedException e) {} } } }

CHAPITRE 7. THREADS

La seconde mthode est dimplmenter linterface Runnable. Comme prcdemment, il sagit en fait dcrire une mthode run()
public class T2 implements Runnable { private int nb= 0; // Compte jusqu 1000000 public void run() { while (nb < 100000000) { nb++; } } public String toString() { return "" + nb; } }

7.3

Lancement dun thread

Un thread se lance grce la mthode start(). Une fois le thread lanc, sa mthode run() sexcute. Lorsque cette mthode se termine, le thread meurt. Un thread dni par hritage (premire mthode) se lance de la manire suivante :
// Cration dun objet thread : MonThread t1= new MonThread(); // Pour linstant, rien ne se passe. // On lance le thread : t1.start();

Pour lancer un thread dni par implmentation (seconde mthode), il faut dclarer deux objets : un objet o1 de la classe implmentant Runnable, et lautre de classe Thread. Ce dernier prendra o1 comme paramtre de son constructeur. Il suft ensuite dappeler la mthode start() du thread.
// On cre un objet de la classe implmentant Runnable : MonRunnable monrun= new MonRunnable(); // On cre un thread Thread secondThread= new Thread(monrun); // On lance le thread secondThread.run();

7.4. LE PARTAGE DU TEMPS

27

Une fois les threads lancs, leur excution se fait en parallle. Notez que le rsultat dune telle excution nest pas dterministe, et dpend de la machine virtuelle java. Voici un exemple utilisant les deux classes dnies prcdemment :
public class Th1 { public static void main(String arg[]) { T1 t1= new T1(); T2 t2= new T2(); Thread t3= new Thread(t2); t1.setK(t2); t1.start(); t3.start(); while (true) { System.out.println("ici main"); try { Thread.currentThread().sleep(10000); } catch (InterruptedException e) {} } } }

Une excution de cet exemple afche :


[rosmord@djedefhor Cours]% java Th1 ici main 0 17489761 ici main 35044086 ici main 100000000 100000000 100000000 100000000 etc...

7.4

Le partage du temps

Sur la plupart des systmes, le multitche est simul. Sur un systme monoprocesseur, un instant t donn, un seul thread est en train de tourner. Pour donner limpression du multitche, un systme comme comme Unix interrompt assez souvent le processus qui tourne , puis choisit un nouveau processus, qui tourne son tour pendant quelques millisecondes, et ainsi de suite. On appelle ordonnanceur (en anglais : scheduler) le programme qui choisit le processus qui va tourner.

7.4.1 Priorits
Les priorits aident lordonnanceur de la machine virtuelle java choisir le thread qui va tourner. Parmis tous les threads candidats, java choisit lun de ceux qui ont la priorit la plus

28

CHAPITRE 7. THREADS

importante. La priorit est un entier entre 0 et 10, associ un thread. On peut la consulter et la modier grce deux mthodes de Thread, getPriority et setPriority. int getPriority () Rcupre la priorit actuelle de lobjet thread auquel la mthode est applique. void setPriority (int pri) throws SecurityException, IllegalArgumentException xe la priorit de lobjet thread auquel la mthode est applique. la valeur de pri doit tre comprise entre Thread.MIN_PRIORITY (0) et Thread.MAX_PRIORITY (10).

7.4.2 La mthode yield()


Java ne garantit absolument pas que deux threads seront vraiment excuts en parallle. En gnral, sur une machine monoprocesseur, un instant donn, seul un des threads tourne. Le multitche est simul en interrompant frquemment le thread qui tourne pour passer la main lautre. Un observateur externe a limpression que les deux threads fonctionnent en mme temps. Le problme est double : 1. interrompre le thread qui tourne ; 2. choisir un thread qui va tourner Les spcications de java ne prcisent pas quand cela doit se produire. Il est donc en thorie possible que dans certaines implmentations un thread ne rende jamais la main et que seul un des threads puisse donc tourner. Pour viter cela, java propose la mthode yield(). Le thread sur lequel on appelle cette mthode rend la main. La machine virtuelle choisit alors un thread excuter parmis les threads excutables de plus haute priorit. Il faut noter qu certain moments, un thread, mme de haute priorit, peut ne pas tre excutable (par exemple, sil attend un vnement) ; il est donc possible quun thread tourne alors quil existe des threads de plus haute priorit, si ceux-ci sont bloqus.

7.5

Variables partages

Comme nous lavons dit en introduction, la grande diffrence entre les threads et les processi Unix rside dans la gestion de la mmoire. La mmoire dun processus Unix est a priori inaccessible depuis les autres processi. Grce cela, un programme Unix mal crit ne peut pas polluer lespace mmoire des autres programmes. De plus, la n dun programme Unix, toute la mmoire utilise est libre. Par contre, comme les espaces mmoire sont spars, il nest pas possible de les utiliser pour communiquer entre processi 1
1. Il est cependant possible dutiliser de la mmoire partage, mais il faut le demander explicitement.

7.5. VARIABLES PARTAGES

29

Lespace mmoire utilis par les threads est, quand lui, partag. Tous les threads dun mme programme peuvent potentiellement modier et lire toutes les variables utilise dans le programme. Cela permet plusieurs threads de communiquer entre eux par le biais des variables, en modiant ou en lisant leurs valeurs (voir le dernier exemple de 7.3, dans lequel les deux threads t1 et t3 lisent et modient la variable t2.nb). Lennui, cest que laccs en parallle une mme ressource pose des problme thoriques. Considrons les deux pseudo-codes suivants :
1 2 3

thread 1 a= x; a++; x= a;

1 2 3

thread 2 b= x; b--; x= b;

Supposons que ces deux threads sexcutent en parallle, et que x soit une variable partage entre les deux. Supposons de plus que la valeur initiale de x soit 0. Si le thread 1 sexcute dabord, et le thread 2 ensuite, x vaudra 0 au nal. Supposons par contre le comportement suivant (1.3 dsigne la ligne 3 du thread 1) :
1.1 2.1 1.2 2.1 1.3 2.3 a= x; b= x; a++; b--; x= a; x= b;

Alors, x vaudra -1. En supposant que, par contre, 1.3 sexcute aprs 2.3, x vaudra +1. Bref, selon le comportement du programme, qui est absolument imprvisible, x vaudra soit 0, soit 1, soit -1. Ce comportement alatoire a peu de chance de correspondre ce que recherchait le programmeur. La solution utilise est de garantir que certaines portions de code ne seront pas excutes en parallle. On considre la variable x comme une ressource. Lors dune criture, un seul processus doit y avoir accs.

7.5.1 Synchronized
La dclaration synchronised permet de verrouiller un objet : si deux fonctions sont synchronises sur un objet, elles ne pourront sexcuter en parallle. Il existe deux possibilits dutilisation de synchronized : lune dans le corps du code, lautre dans une dclaration de mthode. Code synchronized La dclaration synchronized permet de verrouiller un objet. Elle a la forme :
synchronized (obj) { code ..... }

30

CHAPITRE 7. THREADS

Son effet est le suivant : pour excuter le code, la mthode doit verrouiller lobjet. Si celui-ci nest pas dj verrouill, tout va bien. Sinon, lexcution du thread est suspendue jusqu ce que lobjet soit libr par lautre thread qui lutilisait en le verrouillant. ce moment, un des threads qui veulent verrouiller lobjet obtient le verrou, et les autres threads qui veulent un verrou restent suspendus. Pour rendre dterministe le code prcdent, il sufrait donc dcrire :
1 2 3 4 5

thread 1 synchronized (x) { a= x.getValue(); a++; x.setValue(a); }

1 2 3 4 5

thread 2 synchronized (x) { b= x.getValue(); b--; x.setValue(b); }

Mthode synchronized On peut aussi synchroniser le code dune mthode toute entire. Dans ce cas, lobjet verrouill est celui auquel la mthode sapplique. Cela scrit :
public void synchronized increment() { int a= getValue(); a++; setValue(a); }

Fonctionnement de synchronized chaque objet Java est associ un verrou. Une mthode ou un bout de code synchronized doit obtenir ce verroux pour tourner. Une fois que le verroux est obtenu, il est conserv jusqu la n de la mthode ou de la section synchronized. Si un thread essaie dexcuter du code synchronized alors que le verroux ncessaire nest pas disponible, le thread est mis en attente. Lorsque le verroux sera disponible, il pourra peut-tre lobtenir. En pratique, dans la plupart des cas, si un objet est utilis par plusieurs threads la fois, il vaut mieux que les mthodes de cet objet soient synchronized. Si cela nest pas le cas, on peut utiliser des blocs synchronized ou alors encapsuler la classe relle de lobjet dans une classe dont les mthodes seront synchronises.

7.5.2 Volatile
Le compilateur peut conserver une copie locale dune variable, pour des raisons defcacit. Normalement, on na pas de problme si on verrouille les variables correctement. Quand une variable est volatile, toute modication ou consultation est effectivement ralise sur la variable partage. class Test {

7.6. CONTRLE DE LEXCUTION

31

static volatile int i = 0, j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } } } Si one() et two() sont excutes concurremment, sans volatile , two() peut ventuellement observer des cas o j serait plus grand que i. (par exemple, si la valeur de j est rcupre, mais pas celle de i). Avec volatile, non. Cependant, la seule mthode vraiment sre est de passer par synchronized !

7.6

Contrle de lexcution

7.6.1 Arrt dun thread


Pour arrter un thread, la marche suivre est celle de lexemple suivant :
// dmo darrt des threads arrt de thread

// Thread hritant de la classe thread : class T4 extends Thread { boolean continuer= true; public synchronized void arreter() { continuer= false; } public synchronized boolean getContinuer() { return continuer; } public void run() { int k=0; while (getContinuer()) { System.out.println("hello"); yield(); } } } public class Th3 { public static void main(String arg[]) { T4 t= new T4(); t.start(); while (true) { System.out.println("ici main"); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) {}

32
t.arreter(); } } }

CHAPITRE 7. THREADS

Le thread t tourne tant que sa variable interne continuer est true. En la mettant false, on arrte t. Notons cependant que cet arrt nest pas brutal. Il se produit uniquement quand le test de la boucle est atteint.

7.6.2 Attente de la n dun thread


Pour attendre quun thread se termine, nous disposons de la mthode join : void join () t.join() bloque le thread courant (qui nest pas le thread t), jusqu ce que le thread t soit termin. Notez que si t est dj termin, join() revient immdiatement. join() se termine aussi immdiatement si le thread t nest pas encore dmarr. Cette mthode peut savrer utile dans un certain nombre de cas. Supposons par exemple que nous crivions un jeu en rseau. Chaque joueur sidentie, et quand lidentication est termine, le jeux peut commencer. Une premire version de lalgorithme serait :
pour j= 1 jusqu nbrJoueurs identifier(j); commencerJeux();

Cependant, cette version impose aux joueurs des contraintes articielles : le joueur 0 sidentie forcment avant le joueur 1, qui lui-mme sidentie forcment avant le joueur 2, etc... Si lidentication demande une intraction forte entre les clients et le serveur, cette solution nest pas intressante. On pourrait donc faire identier chacun des joueurs en parallle dans des threads :
ThreadIdent t[]= new ThreadIdent[nbrJoueurs]; pour j= 1 jusqu nbrJoueurs t[i]= new ThreadIdent(i); t[i].start();

Mais alors, il est ncessaire pour commencer jouer dattendre que tous les threads de t soient termins :
pour j= 1 jusqu nbrJoueurs t[i].join();

7.7. VITER LES ATTENTES ACTIVES AVEC WAIT ET NOTIFY

33

7.6.3 Mthode sleep


La mthode sleep endort le thread courant pour un certain nombre de millisecondes. Il existe une mthode interrupt qui rveille un thread endormi. Quand cela se produit, la mthode sleep renvoie une InterruptedException. La mthode sleep peut tre intressante dans des contextes o on ne gre quun seul thread. Dans ce cas, on lapplique au thread courant en utilisant la ligne :
Thread.sleep(1000);

static void sleep (int millis) throws InterruptedException endort le thread courant pour millis millisecondes. void interrupt () interrompt le sommeil dun thread (en wait() ou en sleep()).

7.7

viter les attentes actives avec wait et notify

7.7.1 Introduction
Supposons que nous ayons un systme multitche, par exemple un serveur web. Le systme est compos de deux types de threads : un thread serveur, dont le code est :
tant que vrai si requete.existe() requete.executer()

et des threads clients dont le code cre des requtes. Le problme est le suivant : le code du serveur effectue ici ce que lon appelle une attente active, cest--dire quil passe son temps tester sil doit travailler. Or cette boucle consomme beaucoup de temps CPU, et ce alors mme que le thread est sens ne rien faire, ce qui est tout de mme paradoxal. La combinaison des mthodes wait et notify permet de rsoudre le problme. Pour simplier, disons que wait permet de bloquer un thread jusqu ce quun autre thread le rveille avec notify().

7.7.2 Mthodes
void wait () throws InterruptedException mthode de la classe Object. Pour appeler x.wait(), il faut se trouver dans une mthode ou un bloc synchronis sur lobjet x.

34

CHAPITRE 7. THREADS
Le thread courant se bloque, en attendant dtre reveill par un appel de notify ou notifyAll. Dautre part, le verrou quil dtenait sur x est relch, ce qui permet dautres threads synchroniss sur x de travailler.

void notify ()

throws IllegalMonitorStateException x.notify() rveille un des threads qui mis en attente par x.wait(). Le choix effectu est arbitraire. Notez que cela ne signie pas que le thread en question va forcment avoir la main tout de suite. Si aucun thread nest en attente, notify ne fait rien.

void notifyAll ()

throws IllegalMonitorStateException notify() est intressant quand les threads rveiller sont plus ou moins quivalents. Si un seul des threads en attente sur un wait() est susceptible de pouvoir travailler, rien ne garantit que notify rveillera prcisment celui-l. Dans ce cas, notifyAll peut savrer un bon choix. x.notifyAll() rveille tous les threads en attente sur x

Attention ! Ne confondez pas les threads en attente par la suite dun wait() et les threads qui essaient dobtenir un verrou pour commencer une fonction synchronized. notify() naura aucun effet sur ces derniers.

7.7.3 Utilisation de wait et notify


Typiquement, wait et notify sutilisent comme suit : on a un thread serveur, et un ou plusieurs threads clients. Tous partagent un mme objet. Lide est que quand un client ajoute des donnes dans lobjet, le serveur doit se mettre travailler. Supposons donc que lobjet soit de classe Compteur, avec les mthodes :
boolean estInitialis(); void initialise(int v); // get renvoie la valeur et fixe estInitialis faux. int get();

Une premire version du serveur pourrait tre :


while (true) { if(compteur.estInitialis()) { int v= compteur.getValeur(); // On travaille.... } }

Mais ce code correspond une attente active. En fait, le code correct sera, pour le serveur :

serveur sans attente active while (true) { synchronized (requete) {

7.7. VITER LES ATTENTES ACTIVES AVEC WAIT ET NOTIFY


// On attend quil se passe quelque chose sur // requete (quun client appelle notify()) while (requete.estVide()) requete.wait(); v= requete.getValeur(); // Vide la requte } // On travaille.... }

35

Le code du client sera :


... synchronized (requete) { if (requete.estVide()) { requete.initialise(1); requete.notify(); } } ...

client

Comment cela fonctionne-t-il? Lorsque le serveur se lance, il prend le verrou sur compteur. Puis il rentre dans la boucle. Si le compteur na pas de valeur, le serveur se met en attente et relche le verrou. Lorsquun client initialise le compteur, il effectue ensuite un notify, qui interrompt le wait. Le serveur peut nouveau tourner 2 . Lorsquil a la main, il reprend son excution, et comme estInitialis est vrai, il excute le code qui suit.

7.7.4 Client et serveur sans attente active


Dans lexemple prcdent, le client essaie denvoyer une requte, et, si ce nest pas possible, passe autre chose. Seul le serveur attend. Il est possible de faire attendre les clients comme le serveur. Le problme qui se pose alors est que notify ne prvient quun seul thread. Il nest pas garanti que ce soit le bon. Par exemple, si un client pose une requte, le notify peut trs bien rveiller, non le serveur, mais un autre client, ce qui ne sert rien. Pour rsoudre ce problme, il est possible dutiliser notifyAll, qui rveille tous les threads qui effectuent un wait sur une variable donne. Le code du serveur devient alors :
serveur sans attente active while (true) { synchronized (requete) { // On attend quil se passe quelque chose sur // requete (quun client appelle notifyAll()) while (requete.estVide()) requete.wait(); v= requete.getValeur(); // Vide la requte

2. Mais cela ne signie pas quil reprenne la main immdiatement. Il est toujours en concurrence avec les autres threads. Pour que le serveur ait immdiatement la main, il sufrait nanmoins de lui donner une priorit suprieure celle des clients.

36

CHAPITRE 7. THREADS
requete.notifyAll(); // Prvient tout le monde que requte est modifie } // On travaille....

et le code du client :

client // On travaille ... synchronized (requete) { // On attend que la requte soit libre : while (! requete.estVide()) requete.wait(); requete.initialise(1); requete.notifyAll(); } // On travaille ...

Lorsquun client dpose une requte, il prvient le serveur et les autres clients en attente. Mais ce nest pas gnant : le serveur va pouvoir travailler, et les autres clients, comme la requte est occupe, vont se remettre en wait.

7.7.5 Gestion dune le de messages


Lexemple PileAttente.java correspond un cas frquent : le serveur reoit une liste de messages quil doit traiter, de prfrence dans lordre darrive.
PileAttente.java /** * Dmo dun programme de gestion dvnements. * On a larchitecture suivante : * n Threads clients qui envoient des vnements un serveur * un Thread qui gre la pile des vnements * un thread qui effectue les traitements * * Le but de ce programme dexemple est dviter une * attente active de la part du serveur. * En effet, lalgorithme le plus simple pour le serveur serait : * while (true) { * if (! pile.empty()) * v= depiler() * traiter(v); * yield(); * } * * qui consomme beaucoup de CPU pour rien. */ import java.util.*; class Client extends Thread {

7.7. VITER LES ATTENTES ACTIVES AVEC WAIT ET NOTIFY


PileAttente serveur; Random attente; int id; int temps; public Client(PileAttente serveur, int id, int temps, Random r) { this.serveur=serveur; this.id= id; this.temps= temps; attente= r; } public void run() { while(true) { try { sleep(attente.nextInt(1000* 2* temps)); } catch (InterruptedException e) {}

37

System.out.println("Le Thread " + id + " va empiler " + temps); serveur.empiler(temps); System.out.println("Le Thread " + id + " a empil " + temps); // yield(); } } } public class PileAttente extends Thread { /** * traiter attends val secondes, puis affiche val. */ Stack pile; public PileAttente() { pile= new Stack(); } public void traiter(int val) { System.out.println("On traite"); try { sleep(val* 1000); } catch (InterruptedException e) {}; System.out.println("Fin du traitement "+ val); } public void run() { while (true) { System.out.println("Le serveur veut lire une valeur "); int x= depiler(); System.out.println("Le serveur a lu " + x);

38
traiter(x); } }

CHAPITRE 7. THREADS

public synchronized void empiler(int v) { pile.push(new Integer(v)); notify(); // On pourrait mettre aussi notifyAll, en prvision du cas o // lon aurait plusieurs *serveurs*. Mais notifyAll serait-il // intressant ? Si plusieurs threads sont en attente pour // dpiler, ils sont quivalents. Il suffit donc den prvenir un. // do notify. } public synchronized int depiler() { int v; while (pile.empty()) { try { wait(); // On attends un notify. } catch (InterruptedException e) {}; } System.out.println("Le serveur est rveill et va lire"); v= ((Integer)pile.pop()).intValue(); return v; } public static void main(String args[]) { PileAttente s= new PileAttente(); Random r= new Random(); Client c1= new Client(s, 1, 5, r); Client c2= new Client(s, 2, 7, r); Client c3= new Client(s, 3, 10, r); s.start(); c1.start(); c2.start(); c3.start(); } }

7.8

Dmons

En premire approximation, un programme java sarrte quand tous les threads se sont arrts. Or, certains threads servent uniquement fournir des services aux autres ; leur code a gnralement la forme :
public void run() { while (true) {

7.9. GRAPHISMES
si requete traiter_requete(); sleep(1000) } }

39

Un thread avec un tel run() ne sarrterait jamais. Pour simplier la vie du programmeur, Java introduit la notion de dmon. La machine virtuelle java sarrte en fait quand les seuls threads qui tournent sont des dmons. on dclare un thread comme dmon grce la mthode setDaemon : public void setDaemon (boolean d) dclare le thread comme un dmon si d est true. Attention, ne peut tre utilise sur un thread une fois quil est lanc.

7.9
va :

Graphismes

Quand un programme graphique est lanc, java dmarre un thread, la boucle graphique, qui recevoir les vnements graphiques (clics de souris, fentre visible...) ; les traiter (en appelant les listeners correspondants) ; soccuper de lafchage. En consquence, si un programme graphique effectue un traitement long, lintgralit du programme est gel pendant ce temps : pas dafchage, ni de rponse aux actions de lutilisateur. Plusieurs solutions sont disponibles : lutilisation dun Timer swing (en particulier quand on veut une animation), le package spin (http://spin.sourceforge.net), et les threads. Lide est de placer lopration longue dans un thread. Ainsi, linterface graphique se contentera de mettre en place le thread, et de le lancer.
import java.awt.*; import java.awt.event.*; import javax.swing.*; Rebonds.java

// Observateur public class Rebonds extends JPanel { Billard billard; public Rebonds (Billard b) { billard= b; } public void paintComponent(Graphics g) { // Dessiner le fond. Obligatoire pour un bon fonctionnement !

40

CHAPITRE 7. THREADS
super.paintComponent(g); int x, y; // Erreur possible dans les deux lignes suivantes ! // Laquelle ? x= billard.getX(); y= billard.getY(); x= (x * getWidth()) / billard.WIDTH; y= (y * getHeight()) / billard.HEIGHT; g.fillOval(x - 3, y - 3, 6, 6); } public static void main(String args[]) { Billard b= new Billard(10, 31); Rebonds r= new Rebonds(b); Mouvement mouvement= new Mouvement(r, b); JFrame jf= new JFrame(); jf.getContentPane().add(r); jf.setSize(200,200); jf.setVisible(true); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }}); mouvement.setPriority(10); mouvement.start(); }

} // Modle class Billard { // Position de la balle private int x,y; public final static int WIDTH= 100; public final static int HEIGHT= 100; public Billard(int x, int y) {setPos(x,y);} synchronized public int getX() {return x;} synchronized public int getY() {return y;} synchronized public void setPos(int x, int y) {this.x= x; this.y= y;} } // Action class Mouvement extends Thread { Rebonds rebonds; Billard billard; // Direction de la balle int dx; int dy;

7.9. GRAPHISMES

41

public Mouvement(Rebonds rebonds, Billard billard) { this.rebonds= rebonds; this.billard= billard; dx= 1; dy= 2; } public void run() { while (true) { int x= billard.getX(); int y= billard.getY(); if (x + dx < 0 || x + dx > billard.HEIGHT) dx= -dx; if (y + dy < 0 || y + dy > billard.HEIGHT) dy= -dy; billard.setPos(x+dx, y+dy); // se rappeler de prvenir rebonds !!! rebonds.repaint(); yield(); try { sleep(0,01); } catch (InterruptedException e) {} } } }

Le code qui prcde montre lutilisation dun thread, en loccurrence pour lancer une animation. Mais cest valable pour tout traitement un peu long. Lerreur voque dans le code est la suivante : si le thread modie la position du point entre lexcution de x= billard.getX(); et celle de y= billard.getY();, la balle sera afche une position fausse. La solution serait de fournir une mthode getPosition synchronise.

7.9.1 synchronisation et graphismes


La plupart des mthodes de SWING ne sont pas synchronises. A priori, seul la boucle graphique devrait donc manipuler les objets swing. Certaines mthodes sont cependant sres : on peut ainsi utiliser repaint sans problme. Pour les autres manipulations : utiliser SwingUtilities.invokeLater(Runnable) ou utiliser SwingUtilities.invokeAndWait(Runnable) qui insrent les actions dans la liste dvnements de SWING.

42

CHAPITRE 7. THREADS

43

Deuxime partie Bibliothques particulires

45

Chapitre 1 Les Collections


1.1 Introduction

Les collections sont un ensemble de classes de java qui permettent dorganiser des donnes en tableaux, ensembles, dictionnaires, etc... les collections fournissent de plus une sparation entre leur implmentation effective et leur usage, permettant ainsi une meilleure rutilisabilit. Pour cela, on utilise lhritage et les interfaces. Voici tout dabord un exemple de code :
1 2 3 4 5 6 7 8 9 10 11 12

import java.util.*; public class TestCollec { public static void main(String argc[]) { Set promotion= new TreeSet(); promotion.add(new Etudiant(1, "Turing")); promotion.add(new Etudiant(2, "Babbage")); if (promotion.contains(new Etudiant(4, "Wirth"))) System.out.println("Wirth appartient la promotion"); } }

ligne 1 les collections sont dans le package java.util ligne 6 on cre une collection de classe TreeSet, et on la range dans un handle vers un Set. Nous reviendrons sur cette ligne. ligne 7 On ajoute un nouvel tudiant dans lensemble promotion , laide de la mthode add. ligne 9 On teste si Wirth appartient la promotion, grce la mthode contains. La ligne 6 est trs importante. Ce que lon veut, dans la suite du programme, cest un ensemble et en java, cela signie un objet qui implmente linterface Set . Peu importe,

46

CHAPITRE 1. LES COLLECTIONS

pour la suite, la manire dont cet ensemble est implment. Par contre, lors de la cration de cet ensemble, nous sommes bien forc de choisir un implmentation effective. Nous choisissons ici TreeSet (implmentation dun ensemble grce un arbre). Un point important est que nous ne prcisons nulle part que TreeSet est un ensemble dtudiants. En fait, TreeSet est un ensemble dObject (pour ce type particulier densemble, on a de plus lobligation que les objets en question implmentent linterface Comparable, cest--dire quils possdent une mthode compareTo).

1.2

Itrateurs

Supposons que nous ayons rang des etudiants dans un tableau. Lafchage de lensemble des tudiants se ferait de la manire suivante :
for (int i=0; i< tabEtuds.length; i++) System.out.println(tabEtuds[i]);

Supposons que nous ayons cr un type liste dtudiants . Nous le parcourrions de la manire suivante :
for (ListeEtud l= listeEtuds; l != null; l= l.next) System.out.println(l.getEtud());

Du point de vue de limplmentation, ces deux approches sont trs diffrentes. Par contre, du point de vue de lutilisation, on remarque que l et i sont similaires. Ils disposent chacun des fonctionnalits suivantes : on les initialise au dbut de lensemble (i=0, l= listeEtuds) ; on dispose dun oprateur pour passer llment suivant : (i++ et l= l.next) ; on dispose dun test darrt : i < tabEtuds.length et l != null ; on dispose dune opration pour rcuprer llment courant : tabEtuds[i] et l.getEtud(). De plus, ces quatre oprations permettent conceptuellement de parcourir nimporte quel ensemble. En java, ce concept est actualis par linterface Iterator. Le code prcdent peut alors scrire, pour nimporte quelle collection, de la manire suivante :
for (Iterator i= promotion.iterator(); i.hasNext(); ) { Etudiant e= (Etudiant) i.next(); 1 System.out.println(e); }

1.3. ORGANISATION DES CLASSES

47

Remarquez que cest promotion qui construit litrateur. Cest encore un usage de lhritage ! Les oprations vues prcdemment tant reprsentes comme suit : Cration, initialisation La cration dun itrateur est effectue par la collection elle-mme, par lappel de la mthode iterator() ; Rcupration de llment courant et avancement La mthode next() renvoie la valeur de llment courant, puis avance dun cran (cf. i++ en C). Test darrt La mthode hasNext retourne vrai sil est possible dappeler next()

1.3

Organisation des classes

Lorganisation de larbre dhritage pour les collections est le suivant : Les interfaces dnissent les grandes lignes de ce que peut faire une collection :
interface java.util.Collection interface java.util.List interface java.util.Set interface java.util.SortedSet interface java.util.Map interface java.util.SortedMap interface java.util.Map.Entry

Les classes sont organises comme suit :


class java.util.AbstractCollection (implements java.util.Collection) class java.util.AbstractList (implements java.util.List) class java.util.AbstractSequentialList class java.util.LinkedList (implements java.util.List) class java.util.ArrayList (implements java.util.List) class java.util.Vector (implements java.util.List) class java.util.Stack class java.util.AbstractSet (implements java.util.Set) class java.util.HashSet (implements java.util.Set) class java.util.TreeSet (implements java.util.SortedSet) class java.util.AbstractMap (implements java.util.Map) class java.util.HashMap (implements java.util.Map) class java.util.TreeMap (implements java.util.SortedMap) class java.util.WeakHashMap (implements java.util.Map)

Donnons les clefs pour comprendre ces interfaces et ces classes. Tout dabord, conceptuellement : les listes (List) sont des suites dlments. On peut, soit les parcourir du premier au dernier, soit accder au ie lment ;
1. On remarquera un problme de conception d la reprise dhabitudes provenant du C. Il serait bien plus souple et plus gnral de couper next() en deux oprations : une qui avance dans la liste, lautre qui permet de rcuprer un lment.

48

CHAPITRE 1. LES COLLECTIONS


les ensembles (Set) ne comportent pas de doublets. Un lment appartient un ensemble ou ne lui appartient pas. Contrairement aux listes, on ne peux pas choisir o insrer un lment. Les SortedSet sont des ensembles tris, cest--dire que les lments seront rangs du plus petit au plus grand (selon la mthode compareTo). les dictionnaires (Map) sont des tableaux associatifs. Cest--dire des tableaux dont les indices sont dun type quelconque. On peut par exemple avoir comme indice une chane de caractres, et crire des choses comme :
definitions.put("chauve-souris", "mammifre insectivore volant");

La dernire interface, Map.Entry, permet de manipuler un dictionnaire comme un ensemble (Set) de dnitions. En ce qui concerne les classes, elles fournissent des implmentations de ces interfaces. Le choix de la classe utilise dpend de lusage que lon veut en faire 2 . LinkedList fournit une liste doublement chane. Lajout dun lment est rapide, mais la recherche dune valeur donne et laccs au ie lment sont en O(n). ArrayList est une implmentation base de tableau. Lajout dun lment peut tre plus coteux que dans le cas dune LinkedList si le tableau doit grossir, mais par contre laccs au ie lment est en temps constant. Vector est un quivalent de ArrayList datant du jdk1.0. Les diffrences entre les deux se situent surtout lorsque lon utilise le multitche 3 . Stack est un type spcial de vercteur, utilis pour raliser des piles. Les piles sont des structures de donnes trs utiles, dont nous reparlerons. Pour le reste : Hash signie que limplmentation utilise un algorithme de hachage : elle associe chaque lment un nombre (par exemple, on pourrait associer une chane de caractre la somme des codes des caractres quelle contient), et elle utilise ce nombre comme indice dans un tableau. Les implmentations par hachage sont gnralement trs rapides pour des volumes moyens de donnes. Par contre, elles ne permettent pas de rcuprer les lments dans lordre. Tree signie que limplmentation utilise un arbre. Les arbres sont des structures trs robustes, adaptes de grands volumes de donnes. De plus, ils permettent de rcuprer les lments dans lordre croissant.
2. Nous ne parlerons pas ici des WeakHashMap, qui sont trop techniques pour cette premire approche 3. Pour tre complet, disons que Vector est synchronis. Pour comprendre, attendre de voir les Threads

1.4. LINTERFACE COLLECTION

49

1.4

Linterface Collection

Cette interface explicite les fonctionnalits communes toutes les collections.


public interface Collection { // Oprations de base int size(); // Nombre dlments boolean isEmpty(); // la collection est-elle vide ? void clear(); // vide la collection // Oprations sur les lments boolean contains(Object element); // la collection contient-elle element boolean add(Object element); // ajout dun lment (optionnel) boolean remove(Object element); // suppression dun lment (optionnel) // Itrateur Iterator iterator(); // rcupre un itrateur sur le premier lment // Opration inter-collections boolean containsAll(Collection c); // la boolean addAll(Collection c); // this = boolean removeAll(Collection c); // this boolean retainAll(Collection c); // this collection inclut-elle c ? this c = this c = this c

// tableaux : Object[] toArray(); // Renvoie le tableau des lments de la collection Object[] toArray(Object a[]); }

Notes : add, addAll, etc... sont des mthodes de Collection qui retournent un boolen, qui prcise si la mthode a modi lensemble auquel elle sapplique. Par exemple, si X = {a, b, c} et que Y = {b, c}, X.addAll(Y) ne modiera pas X, puisque tous les lments de Y sont dans X. Donc X.addAll(Y) renverra false. Par contre, Y.addAll(X) renverrait true. Les mthodes qui doivent chercher un lment (contains, remove...) utilisent les mthodes equals des lments pour les comparer entre eux. La dernire version de toArray permet en fait de rcuprer un tableau typ. On peut crire, par exemple,
String[] x = (String[]) maCollectionDeChaines.toArray(new String[0]);

pour rcuprer dans x un tableau de String. Les itrateurs fournissent les oprations :
public interface Iterator { boolean hasNext(); // Peut-on appeler next ? Object next(); // Retourne llment courant et incrmente void remove(); // Enlve llment courant (opt) }

50

CHAPITRE 1. LES COLLECTIONS

Lopration remove est optionnelle, cest--dire que certaines implmentation de linterface peuvent ne pas en donner de version utilisable. Il faut consulter la documentation.

1.5

Listes

Les listes sont des suites dlments. Lordre des lments est donc important, et est x par le programmeur. Les oprations de List sont les mmes que celles de Collection, plus :
public interface List extends Collection { // Accs direct Object get(int i);\ Rcupre le ie lment Object set(int i, Object elt); // fixe le ie elt. Opt. void add(int i, Object elt); // Ajoute elt en i e position // Dplace les suivants vers la droite Object remove(int i); // enlve le ime elt // Dplace les suivants vers la gauche abstract boolean addAll(int i, Collection c); // ajoute en pos. i les elts de c // Recherche int indexOf(Object o); // Index de la premire occurrence de lobjet o, ou -1 int lastIndexOf(Object o); // Index de la dernire occurrence de lobjet o, ou -1 // Iterateurs ListIterator listIterator(); // Itrateur de liste ListIterator listIterator(int i); // Itrateur de liste sur le i e lment // Sous listes List subList(int from, int to); // sous liste entre from inclus et // to, exclu }

Outre ces oprations, les listes fournissent des itrateurs de liste. Ceux-ci sont dots des oprations supplmentaires :
public interface ListIterator extends Iterator { boolean hasPrevious(); // Passage au prcdent possible ? Object previous(); // passage lobjet prcdent int nextIndex(); // Index suivant int previousIndex(); // Index prcdent void set(Object o); // fixe llment courant o (opt) void add(Object o); // ajoute llment o cette position }

Remarque sur les opration de recherche : contains, remove, retainAll sont spcies pour les liste en utilisant loprateur equals de llment, pas loprateur ==. Notez par contre que les oprations dajout rajoutent un lment, mme sil se trouve dj dans la liste, et

1.6. ENSEMBLES

51

que si remove(Object) supprime la premire occurrence de lobjet, c1.removeAll(c2) garantit quaprs excution, il ny a plus aucun lment contenu dans c2 qui reste dans c1.

1.6

Ensembles

Linterface densemble est la mme que celle de Collection. Il est par contre important de noter les points suivants sur les implmentations.

1.6.1 Ensembles tris


Pour construire un ensemble tri, il faut expliquer comment trier ces lments. Cest automatique si les classes des lments implmentent linterface Comparable. Cette interface dnit une mthode compareTo :
public int compareTo(Object o)

Cette mthode renvoie un entier ngatif, null, ou positif selon que this est (respectivement) infrieur, gal, ou suprieur o. Lautre solution est de fournir un comparateur comme argument au constructeur de lensemble. Un comparateur est un objet dune classe qui dnit la mthode suivante 4 :
int compare(Object o1, Object o2); // Compare o1 et o2 (cf. ci-dessus) // Pour des entier, o1 - o2 fait laffaire

Par exemple, ce comparateur permet de crer un ensemble dentiers tris en ordre dcroissant :
class MonComparateur implements Comparator { public int compare(Object o1, Object o2) { Integer a= (Integer)o1; Integer b= (Integer)o2; return b.intValue()-a.intValue(); } }

On lutilisera ainsi :
Set s= new TreeSet(new MonComparateur()); s.add(new Integer(5)); s.add(new Integer(7)); for (Iterator i= s.iterator(); i.hasNext(); ) System.out.println(i.next());

Ce qui imprime : 7 5 Notez lusage de Integer pour encapsuler un int dans un objet.
4. Ce nest pas lexacte vrit mais cest sufsant en pratique. Pour tout savoir, lire la doc !

52

CHAPITRE 1. LES COLLECTIONS

1.7

Dictionnaires (maps)

public interface Map { // Operations de base // Range la valeur v dans la case k Object put(Object k, Object v); // Rcupre la valeur v associe k Object get(Object k); // Supprime la case de cl k Object remove(Object k); // possde-t-on un case de cl k ? boolean containsKey(Object k); // possde-t-on un case contenant la valeur v ? boolean containsValue(Object v); int size(); boolean isEmpty(); // Oprations globales // Range tous les lments de t dans this void putAll(Map t); void clear(); // Vue comme collections // Ensemble des clefs public Set keySet(); // Ensemble des valeurs public Collection values(); // Ensemble des couple clef/valeurs public Set entrySet(); // Interface pour les lments de entrySet public interface Entry { Object getKey(); Object getValue(); Object setValue(Object value); } }

Notez labsence diterator(). En fait, pour parcourir une Map, on passe par les ensembles (Set), en utilisant, lune des trois mthodes keySet(), values(), ou entrySet(), selon que lon veut parcourir lensemble des clefs, des valeurs, ou des couples clefs/valeurs. On utilise cela de la manire suivante :
Set s= dico.entrySet(); for(iterator i= s.iterator(); i.hasNext(); ) { // Map.Entry (notez lorthographe, il sagit dune sous-classe) // reprsente un couple clef/valeur dans la Map. Map.Entry e= (Map.Entry)(i.next()); System.out.println("clef " + e.getKey() + ", valeur : ", e.getValue()); }

1.8. PILES (STACK)

53

1.8

Piles (Stack)

Une pile est un objet dot des oprations :


boolean empty(); // est-elle vide ? void push(Object o); // empile un objet Object pop(); // dpile un objet Object peek(); // regarde le sommet de la pile

1.9

Exemples

1.9.1 La collection Sac


Nous prsentons ici un exemple jouet de collection, pour montrer, en particulier, le lien entre une collection et son itrateur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

package mesutils; import java.util.*; public class Sac extends AbstractCollection { int utilisees; // nombre de cases utilises Object tab[]; // tableau des objets de la collection // Constructeur public Sac(int capacite) { utilisees=0; tab= new Object[capacite]; } public int size() { return utilisees; } public boolean add(Object o) { tab[utilisees++]= o; return true; // On retourne vrai si la collection a chang } public Iterator iterator() { return new SacIterator(this); } // Test et dmonstration public static void main(String args[]) { Collection c= new Sac(10); c.add("I"); c.add("II"); c.add("III"); c.add("IV"); c.add("V"); c.add("VI"); c.add("VII"); c.add("VIII"); c.add("IX"); c.add("X"); for (Iterator i= c.iterator(); i.hasNext(); ) System.out.println("lment " + i.next());

54
34 35 36 37

CHAPITRE 1. LES COLLECTIONS


// erreur : c.add("XI"); }

} package mesutils; import java.util.*; public class SacIterator implements Iterator { int i; Sac s; // Seul Sac a le droit dappeler le constructeur // Celui-ci a donc la porte package. SacIterator(Sac s) { i= 0; this.s= s; } public boolean hasNext() { return i < s.size(); } public Object next() { return s.tab[i++]; } public void remove() { throw new java.lang.UnsupportedOperationException( "Remove nest pas implmente pour les sacs"); } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

1.9.2 Utilisation de Map pour compter des mots


Le programme suivant lit un chier, ligne par ligne, et afche ensuite le nombre de fois o chaque ligne apparat.
1 2 3 4 5 6 7 8 9 10 11 12

import java.util.*; import java.io.*; public class TestMaps { public static void main(String args[]) throws IOException { BufferedReader f= new BufferedReader(new InputStreamReader(System.in)); String s; Map dico= new TreeMap(); // Dictionnaire tri while ((s= f.readLine()) != null) { int nb= 0; if (dico.containsKey(s)) nb= ((Integer)dico.get(s)).intValue();

1.9. EXEMPLES
13 14 15 16 17 18 19 20 21 22 23 24 25 26

55

// nb contient maintenant le nombre doccurrences du mot. dico.put(s, new Integer(nb + 1)); } f.close(); // Affichage : Set entrees= dico.entrySet(); for(Iterator i= entrees.iterator(); i.hasNext();) { Map.Entry e= (Map.Entry)(i.next()); System.out.println(e.getKey() + " apparat " + e.getValue() + " fois"); } } }

Voici un exemple dutilisation :


[rosmord@djedefhor Cours]$ java TestMaps aa ppp aa ll l mmm l aa b o a (Contrle-D) a apparat 1 fois aa apparat 3 fois b apparat 1 fois l apparat 2 fois ll apparat 1 fois mmm apparat 1 fois o apparat 1 fois ppp apparat 1 fois

56

CHAPITRE 1. LES COLLECTIONS

57

Chapitre 2 Entres/sorties
INTGRER LES EXEMPLES DES TRANSPARENTS

2.1

La classe File

La classe File permet de manipuler des chiers et des rpertoires de lextrieur : elle fournit les fonctionalits ncessaires pour connatre les droits sur un chier, le dtruire, le dplacer, lister des rpertoires, etc... Par contre elle ne fournit rien pour crire dedans. Pour voir ce que permet la classe File, voici un petit programme qui dtruit les chiers de sauvegardes crs par emacs (leur nom se termine par ~ ).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

import java.io.*; // // // // //

Clean.java

FilenameFilter est une interface utilise par listFiles pour ne lister quune partie des fichiers. Chaque fichier du rpertoire est test par la mthode accept(...), qui renvoie true si le fichier doit apparatre. Ici, nous vrifions que le nom du fichier se termine par "~".

public class Clean implements FilenameFilter { public boolean accept(File dir, String name) { return (name.charAt(name.length() -1) == ~); } static public void main(String args[]) { // On cre un filtre pour listFiles. // Comme il sagit dun bte petit programme, // on utilise la classe Clean comme filtre. Clean filter= new Clean(); // dir reprsente le rpertoire nettoyer. // Son nom est pass comme argument. File dir= new File (args[0]); if (dir.isDirectory()) {

58
24 25 26 27 28 29 30 31 32

CHAPITRE 2. ENTRES/SORTIES
// On cre la liste des fichiers // dont le nom se termine par ~ File [] fichs= dir.listFiles(filter); // On efface tous ces fichiers. for (int i= 0; i< fichs.length; i++) fichs[i].delete(); } }

Nous donnons ci-aprs une slections de mthodes utiles fournies par la classe File. public File (String pathname) Cre un nouvel objet File, correspondant au chemin (path) indiqu. Par exemple, avec
File f= new File(".");

f dsignera le rpertoire courant. Le chemin peut correspondre un chier ou un rpertoire. public File (File parent, String child) Cre un nouvel objet File, correspondant au chemin (path) compos en ajoutant child parent. Ainsi, en excutant le code :
File homedir= new File("/home/rosmord"); File f= new File(homedir, "MonProg.java");

f dsignera le chier "/home/java/MonProg.java". boolean canRead () Renvoie vrai si le chier est lisible. boolean canWrite () Renvoie vrai si le chier est autoris en criture. boolean delete () Dtruit le chier ou le rpertoire correspondant. boolean exists () Renvoie vrai si le chier existe. String getName () Retourne le nom du chier. String getPath () Retourne le chemin du chier (nom compris).

2.1. LA CLASSE FILE


String toString () mme chose que getPath. boolean isDirectory () Renvoie vrai si le chier est un rpertoire. boolean isFile () Renvoie vrai si le chier est un chier normal. long lastModified () Retourne la date de dernire modication. long length () Retourne la longueur du chier

59

File[] listFiles () Renvoie la liste des chiers contenus dans this, qui doit bien entendu tre un rpertoire. File[] listFiles () Renvoie la liste des chiers contenus dans this, qui doit bien entendu tre un rpertoire. File[] listFiles (FilenameFilter filter) Idem, mais ne concerne que les chiers slectionns par lter. Voir lexemple de code en introduction. boolean mkdir () Cre le rpertoire correspondant this. boolean mkdirs () this dsigne un rpertoire. Cette mthode le cre, mais cre aussi tous les rpertoires intermdiaires ncessaires, sils nexistent pas. Par exemple, avec le code :
File f= new File("/tmp/rep1/rep2/rep3"); f.mkdirs();

Si ni rep1, ni rep2, ni rep3 nexistent, les trois seront crs. boolean renameTo (File dest) Renomme un chier. boolean setReadOnly () Place un chier en lecture seule. (interdit lcriture, quoi).

60

CHAPITRE 2. ENTRES/SORTIES

2.2

Organisation des classes dentres/sortie

2.2.1 Fichiers en lecture, chiers en criture 2.2.2 Classes orientes octets, classes orientes caractres 2.2.3 Filtrage
Les classes dentres/sorties de Java sont souvent utilises en cascade . Lide tant que le texte lu par un objet sert dentre au suivant. On remarquera que ce systme est assez similaire celui qui est utilis dans les pipe dUnix. Considrons, par exemple, la ligne :
LineNumberReader f= new LineNumberReader(new InputStreamReader(System.in));

On utilise trois objets : System.in, qui est un InputStream, cest dire un chier ouvert en lecture, et lisant des octets. InputStreamReader, qui prend en entre, le ot doctets fourni par System.in, et renvoie des caractres. LineNumberReader : lit les caractres dans lInputStreamReader, et les renvoie. Au passage, en prote pour tenir jour un numro de ligne. Lorsquune instruction comme
c= f.read();

est excute, le cheminement des donnes est le suivant :


Clavier InputStream System.in InputStreamReader (anonyme) LineNumberReader f read() c

chars octets octets chars

Pour mieux comprendre le fonctionnement de ce systme, voyons une petite classe qui fourni les fonctionnalits dun Reader (Lecteur de caractres), mais compte les caractres lus :
import java.io.*; public class CompteReader extends Reader { private Reader in; private int total; // in est le Reader dans lequel nous lirons public CompteReader(Reader in) { this.in= in;

2.3. QUELQUES CLASSES


total= 0; } public int read(char[] s, int off, int len) throws IOException { // On lit dans in, et on rcupre le nombre de caractres // lus dans nbr. int nbr= in.read(s,off,len); // On augmente le total en consquence. total+= nbr; return nbr; } public void close() throws IOException { in.close(); } public int getTotal() { return total; } }

61

Quand on lit une donne dans un CompteReader, avec read(), la mthode read de CompteReader utilise celle du Reader in pour lire effectivement les caractres.

2.3

Quelques Classes
: ces

FileReader, FileWriter, FileInputStream, FileOutputStream classes lisent et crivent dans un chier.

BufferedReader : cette classe utilise un tampon pour lire les donnes, cest--dire que les donnes sont lues par blocs, lesquels sont stocks en mmoire. Lavantage de cette mthode est quelle rduit normalement le nombre daccs disque. Son utilisation est transparente pour le programmeur. Un autre avantage du BufferedReader est la possibilit de revenir en arrire dans la lecture, laide des mthodes mark et reset : void reset () throws IOException remet la tte de lecture la position de la dernire marque pose.

void mark (int limite) throws IOException place une marque la position courante de lecture. largument limite permet de xer le nombre maximum de caractres qui pourront tre lus en prservant la marque. Un autre intrt du BufferedReader est la disponibilit de la mthode readLine : String readLine () throws IOException

62

CHAPITRE 2. ENTRES/SORTIES
renvoie la ligne suivante sous forme de String, ou null si on est la n du chier.

LineNumberReader : un lecteur driv de BufferedReader, mais dot dune mthode getLineNumber qui permet de connatre le numro de la ligne courante. InputStreamReader : cette classe permet de construire un Reader partir dun InputStream. Cest particulirement utile avec System.in. PushbackReader : un lecteur dot dune opration unRead() qui permet de remettre du texte dans le ot dentre, comme sil navait pas dj t lu. CharArrayReader, CharArrayWriter, ByteArrayInputStream, ByteArrayOutputStream, StringReader, StringWriter, StringBufferInputStream : ces classes permettent de lire ou dcrire dans un tableau ou dans une String. Par exemple, le code suivant lit le contenu dun chier texte et le copie dans une String :
int c; FileReader f= new FileReader(args[0]); StringWriter sw= new StringWriter(); while ((c= f.read()) != -1) { // crit c dans sw sw.write(c); } // Copie le contenu de sw dans s. String s= sw.toString(); System.out.println(s);

2.4

Exemples dutilisation

2.4.1 Lecture dun chier


public static void testLectureTexte (InputStream i) throws IOException { InputStreamReader f= new InputStreamReader(i); // Le rsultat de read doit tre un entier // ( cause du -1 qui est renvoy en fin de fichier) int cc; while ( (cc = f.read()) != -1) { // Pour ranger cc dans un char, il faut un cast : char c= (char)cc; ... } f.close(); }

2.5. MTHODES

63

2.5

Mthodes

Nous donnons ici une selection de mthodes utiles, en nous concentrant sur les classes Reader et Writer. Pour les classes InputStream et OutputStream, les noms des mthodes sont les mmes, en remplaant char par byte .

2.5.1 Constructeurs
Les classes orientes chier Ces classes ont toute un constructeur qui prend comme argument un nom de chier, et un constructeur qui prend comme argument un objet File : FileOutputStream (File file) throws IOException FileOutputStream (String name) throws IOException FileOutputStream (String name, boolean append) throws FileNotFoundException Ouvre le chier name en criture, en le crant si ncessaire. Si append est vrai, les critures se feront la n du chier. Si le chier nexiste pas et ne peut pas tre cr, alors une exception FileNotFoundException est leve. FileInputStream (File file) throws FileNotFoundException FileInputStream (String name) throws FileNotFoundException Les classes FileReader et FileWriter ont les mmes constructeurs que FileInputStream et FileOutputStream, respectivement. Les classes OutputStreamWriter et InputStreamReader Ces deux classes permettent de faire le pont entre les classes oriente octets et les classes orientes caractres. Plus prcisment, tant donn un ot orient octets, elles permettent de crer le ot orient caractres correspondant, en encapsulant lobjet-ot dorigine dans un Reader ou un Writer.

64 Les constructeurs disponibles sont : InputStreamReader (InputStream in) OutputStreamWriter (OutputStream out)

CHAPITRE 2. ENTRES/SORTIES

classes orientes chanes Les classes StringReader et StringWriter sont trs simples : StringReader (String s) cre un StringReader qui lit dans s. StringWriter () cre un StringWriter. La chane produite sera rcuprable grce la mthode toString. Les classes de lecture qui travaillent sur des tableaux et non sur des objets sont plus complexes : CharArrayReader (char[] buf) cre un lecteur qui lit dans le tableau buf. CharArrayReader (char[] buf, int offset, int length) cre un lecteur qui lit dans le tableau buf, en commenant offset, et avec une longueur de length (soit donc entre la case offset incluse et la case offset + length exclue). Par contre les classes dcriture ont un constructeur trs simple : CharArrayWriter () Les classes ByteArrayOutputStream et ByteArrayInputStream ont les mmes constructeurs que leurs quivalent en Writer et en Reader, en remplaant les chars par des bytes. Autres classes Les autres classes fonctionnent gnralement comme des ltres. Elles disposent donc typiquement dun constructeur qui prend comme argument un objet de la mme famille que lobjet crer (Writer pour Writer, Reader pour Reader, InputStream pour InputStream et OutputStream pour OutputStream). Ainsi, le constructeur de la classe LineNumberReader est : LineNumberReader (Reader in)

2.5. MTHODES

65

2.5.2 Reader
int read () throws IOException lit un caractre sur lentre, et renvoie son code, ou -1 si la n du chier est atteinte.

int read (char [] buf) throws IOException Remplit le tableau buf avec les caractres lus. Attention, cette mthode nalloue pas le tableau. La mthode renvoie le nombre de caractres lus, ou -1 si la n du chier est atteinte. int read (char [] buf, int dep, int longueur) throws IOException Copie les caractres lus dans buf, en commenant lindice dep, en en lisant au maximum longueur caractres. La mthode renvoie le nombre de caractres lus, ou -1 si la n du chier est atteinte. void close () ferme le lecteur. throws IOException

2.5.3 Writer
Mthodes gnrales void write (int c) throws IOException crit le caractre dont le code est c. Notez que cette mthode fonctionne correctement que c soit un char ou un int.

void write (char [] s) throws IOException crit le contenu de s. void write (char[] s, int off, int longueur) throws IOException crit les caractres de s compris entre lindice off et off + longueur. void write (String s) throws IOException crit la chane s.

66 void flush ()

CHAPITRE 2. ENTRES/SORTIES

throws IOException Ralise effectivement la copie sur le support. Cest utile dans le cas de classes comme BufferedWriter, o les donnes sont stockes temporairement en mmoire.

void close () ferme le Writer FileWriter

throws IOException

La classe FileWriter permet dcrire du texte dans un chier. Son emploi est simple. On notera les deux contructeurs suivants : FileWriter (String name) throws IOException Ouvre en criture le chier de nom name. FileWriter (String name, boolean append) throws IOException Ouvre en criture le chier de nom name. Si append est true, alors lcriture se fera la n du chier, sans craser le texte qui se trouve ventuellement au dbut.

2.6

La classe RandomAccessFile

Cette classe permet douvrir un chier dans lequel on pourra, lire, crire, et se placer nimporte quelle position.

2.6.1 Ouverture et fermeture


RandomAccessFile (String nom, String mode) throws FileNotFoundException Cre un RandomAccessFile ouvert sur le chier nomm nom. Le mode peut tre r pour un chier ouvert en lecture seule, ou rw pour un chier ouvert en lecture/criture. void close () ferme le chier

throws IOException

2.6. LA CLASSE RANDOMACCESSFILE

67

2.6.2 Lecture et criture


Les mthodes de lecture permettent de lire des donnes binaires. int read () throws IOException lit un octet non sign. On a de mme que pour les Reader, des mthodes read un et trois arguments, qui permettent de remplir des tableaux.

On dispose, de plus, des mthodes readBoolean, readByte, readChar, readDouble, readFloat, readInt, readLong, readShort, readUnsignedByte, readUnsignedShort pour lire une valeur dun type de base. Par exemple : boolean readBoolean () throws IOException lit un boolen. Attention, readByte lit un octet sign (entre -127 et 128.) Les mthodes dcriture sont similaires : on a dune part trois mthodes write : void write (byte []b, int dep, int longueur) throws IOException crit les octets du tableau b, de lindice dep lindice dep + 1. et dautre part, une mthode writeXXX par type de base, comme par exemple writeChar. Notez que Java dnit lordre dans lequel sont crit les octets des donnes lues, de manire indpendantes de larchitecture. Ainsi, un chier binaire cr par java sur Macintosh sera utilisable aussi sur PC

2.6.3 Dplacement
long getFilePointer () throws IOException retourne la position courante. void seek (long pos) throws IOException xe la position courante. pos est le nombre de caractres depuis le dbut du chier. La prochaine lecture ou la prochaine criture auront lieu partir de la nouvelle position. throws IOException retourne la longueur de ce chier

long length ()

void setLength (long newLength) throws IOException xe la longueur du chier newLength.

68

CHAPITRE 2. ENTRES/SORTIES

2.7

Srialisation

Java permet dcrire ou de lire directement des objets dans un chier. On utiliser ce systme pour sauvegarder un objet complexe, presque sans effort. On peut, par exemple, crire :
TreeSet s; ... // Code qui remplit s ... ObjectOutputStream o= new ObjectOutputStream(New FileOutputStream("toto.sav")); o.writeObject(s); o.close();

Et le contenu de notre TreeSet sera sauv dans le chier toto.sav . Pour relire les donne, cest peine plus compliqu :
ObjectInputStream f= new ObjectInputStream(New FileInputStream("toto.sav")); TreeSet s= (TreeSet)f.readObject(); f.close();

Remarquez le cast, d au fait que readObject renvoie un Object.

2.7.1 Conditions demploi


Pour sauver un objet dans un ObjectOutputStream, la classe de lobjet doit implmenter linterface (vide) Serializable. De plus, les champs de lobjet doivent eux aussi appartenir des classes Serializable. Ainsi, comme TreeSet est Serializable (voir doc) notre exemple prcdent ne fonctionnera que si les donnes contenues dans le TreeSet sont ellesmmes Serializable. Nous suggrons donc de dclarer Serializable toute classe potentiellement utilisable avec la srialisation. On rappelle que limplmentation dinterface est hritable. Si une classe est Serializable, toutes ses hritires le seront.

2.7.2 Champs non sauvegards


Si un champ est dclar transient, sa valeur nest pas sauve dans le chier.

2.8

La classe StreamTokenizer

2.8.1 Introduction
La classe StreamTokenizer permet de lire de manire souple un chier texte, en le dcoupant en mots. Ces mots sont appels token. Le Tokenizer fonctionne en deux tapes : tout dabord, une mthode (nextToken()) permet de lire le mot suivant. Ensuite, il est possible dinterroger

2.8. LA CLASSE STREAMTOKENIZER

69

le Tokenizer sur la valeur de ce mot, et ventuellement sur son type (par exemple, si cest une chane de caractre, une ponctuation, ou un nombre). Lexemple qui suit prsente une utilisation possible de StreamTokenizer. Il sagit dun petit programme qui lit sur lentre standard. Si on tape des nombres, ceux-ci sont ajout un total. En tapant print , on obtient lafchage de ce total. La difcult pour raliser ce genre de programme est quon ne sait pas a priori ce quon va lire : print ou un nombre. Le programme en lui mme est simple, mais, sans StreamTokenizer, sa programmation serait assez dlicate. Lavantage avec StreamTokenizer est quon lit le token suivant sans se demander ce que cest, et quon prend une dcision aprs sa lecture, ce qui facilite la programmation.
Dmonstration de StreamTokenizer import java.io.*; public class TestTok { public static void addition() throws IOException { double total= 0.0; int token; // Cration dun StreamTokenizer sur lentre standard StreamTokenizer s= new StreamTokenizer(new InputStreamReader(System.in)); // On lit lentre jusqu ce que le texte soit fini while( (token= (s.nextToken())) != StreamTokenizer.TT_EOF) { //Dans token on a le type du mot lu : mot, nombre, ou autre switch (token) { case StreamTokenizer.TT_NUMBER: // Si cest un nombre, sa valeur est dans nval : total+= s.nval; break; case StreamTokenizer.TT_WORD: // Si cest un mot, elle est dans sval if (s.sval.equals("print")) System.out.println("total= " + total); else System.out.println("le mot clef " + s.sval + " est inconnu"); break; // Pour le reste des caractres, le token // a comme valeur le code du caractre default: System.out.println("chane inattendue: " + (new Character((char)token))); } } } public static void main(String args[]) addition(); throws IOException {

70
} }

CHAPITRE 2. ENTRES/SORTIES

En rgle gnrale, le schma de lutilisation dun StreamTokenizer est le suivant :


// Initialisation StreamTokenizer s= .... ; // Configuration : // On appelle des fonctions diverses permettant // De modifier le comportement du StreamTokenizer : s.lowerCaseMode(true); ... // Boucle de lecture : while(s.nextToken() != StreamTokenizer.TT_EOF) { case (s.ttype) { ... } }

2.8.2 Documentation
Constructeurs Il existe deux constructeurs pour les StreamTokenizer, mais lun dentre eux est obsolte. Nemployez donc que le suivant : StreamTokenizer (Reader r) Construit un StreamTokenizer qui lit sur lentre r. Mthodes Les mthodes peuvent tre groupes en deux ensembles : celles qui permettent de congurer le StreamTokenizer, et celles qui sont utilises lors de la lecture du texte. Certaines mthodes de conguration permettent de xer le comportement global dun StreamTokenizer. Par exemple, parseNumbers lui demande danalyser les nombres comme des nombres et non comme des suites de caractres. Dautres mthodes permettent de grer le comportement dun caractre en particulier. void eolIsSignificant (boolean flag) Si ag est true, alors la n de ligne est trait comme un caractre ordinaire . Sinon, on la considre comme un espace. Par dfaut, cest cette seconde option qui est prise. void lowerCaseMode (boolean flag) Si ag est vrai, alors le texte est automatiquement traduit en minuscule, ce qui est utile pour les langages qui ignorent les diffrences majuscules/minuscules (ou diffrences de casse en langage typographique).

2.8. LA CLASSE STREAMTOKENIZER

71

void parseNumbers () Si cette mthode est appele, les nombres seront considrs comme tels. Le StreamTokenizer fourni par dfaut analyse les nombres (do une lgitime interrogation : pourquoi diantre les concepteurs ont-ils fourni cette mthode, qui ne sert rien, et pas de mthode noParseNumbers, qui aurait servi quelque chose. void slashSlashComments (boolean flag) Si ag est vrai, // introduit un commentaire. Le texte qui suit est ignor jusqu la n de la ligne. void slashStarComments (boolean flag) Si ag est vrai, les commentaire de type C sont utiliss. Le texte compris entre /* et */ est ignor. void resetSyntax () Remet le StreamTokenizer zro. Tous les caractres sont alors considrs comme ordinaires . Un caractre ordinaire est trait tout seul, comme par exemple un signe de ponctuation. Les mthodes qui suivent permettent de spcier comment traiter des caractres donns. Par exemple, si lon crit
tok.commentChar(#);

le caractre # introduira une ligne de commentaires (cest dire que la ligne en question sera saute par le StreamTokenizer). void commentChar (int ch) Le caractre ch introduit des lignes de commentaires. void ordinaryChar (int ch) Le caractre ch est considr comme un caractre ordinaire . void ordinaryChars (int low, int hi) Tous les caractres dont les codes sont compris entre low et hi sont considrs comme ordinaires. void quoteChar (int ch) Le caractre ch est utilis comme guillemets. void whitespaceChars (int low, int hi) Tous les caractres dont les codes sont compris entre low et hi sont considrs comme des espaces. void wordChars (int low, int hi) Tous les caractres dont les codes sont compris entre low et hi sont considrs comme des lettres, qui forment des mots.

72

CHAPITRE 2. ENTRES/SORTIES

Mthodes permettant dutiliser le StreamTokenizer : La mthode de loin la plus importante est bien entendu nextToken. On notera le comportement intressant de toString. int lineno () Renvoie le numro de la ligne courante. int nextToken () Lit le token suivant, et renvoie son code. Les espaces et les commentaires sont ignors de manire transparente. Les codes possibles sont : TT_EOF n de chier ; TT_EOL n de ligne (si s.eolIsSignificant(true) a t appel ; TT_WORD un mot a t lu. Un mot est une suite de lettre, cest--dire de caractres dclars comme wordChars. Par dfaut, les lettres sont considres ainsi. TT_NUMBER un nombre (rel) a t lu. autre code : tous autre code signie quun caractre ordinaire (un signe de ponctuation par exemple) a t lu. Le code renvoy est dans ce cas le code du signe lui-mme. Noubliez pas que ces constantes doivent tre prcdes du nom de la classe StreamTokenizer. void pushBack () Remet le dernier token lu sur le ot de lecture. Le prochain nextToken() le relira. Cette mthode nest pas trs souvent utile. String toString () Renvoie le token courant sous forme de chane. Champs Les champs utilisables de StreamTokenizer sont de deux types : des constantes, comme TT_NUMBER ou TT_EOF, et des champs variables, comme nval et sval. Il aurait sans dout t prfrable que ces derniers fussent remplacs par des mthodes. Les constantes sont dcrites dans la documentation de nextToken(), ci-dessus. Les autres champs sont : nval si le dernier token est de type TT_NUMBER, sa valeur numrique. sval si le dernier token est de type TT_WORD, sa valeur sous forme de chane de caractres. Notez que si lon veut la valeur dun token quelconque sous forme de chane, on peut utiliser toString(). ttype type du token courant. Cest la valeur renvoye par le dernier nextToken().

2.8. LA CLASSE STREAMTOKENIZER

73

Dans le cas o on ne veut pas que les nombres soient analyss comme des nombres, il faut rednir la syntaxe de tous les caractres. Le code suivant convient :
StreamTokenizer tok= new StreamTokenizer(....); tok.resetSyntax(); tok.wordChars(a, z); tok.wordChars(A, Z); tok.wordChars(128 + 32, 255); tok.whitespaceChars(0, );

Notez enn que le StreamTokenizer est assez limit, et surtout orient vers lanalyse de code informatique. En particulier, tous les caractres dont les codes sont suprieurs ou gaux 256 sont traits comme des lettres. Pour du texte non informatique, les problmes sont bien plus complexes ; les bibliothques java fournissent le package java.text.

74

CHAPITRE 2. ENTRES/SORTIES

75

Chapitre 3 Java et les bases de donnes


Jdbc : Java Data Base Connectivity.

3.1

Introduction JDBC

1. Ncessit dutiliser un langage appropri pour interroger une base de donne (SQL) ; 2. Ncessit dun systme client serveur cause des restrictions des applets.

3.2

Architecture
Application java Applet Java

JDBC

interface jdbc du Moteur

Moteur de bases de donne

3.3

Un exemple : postgres
les sources, dans

Linterface jdbc est distribue avec postgresql-6.2/src/interfaces/jdbc ;

une fois compile, la bibliothque est utilisable sous tout ordinateur ;

76

CHAPITRE 3. JAVA ET LES BASES DE DONNES


Les sources qui lutilisent doivent contenir la ligne :
import java.sql.*;

Pour spcier le driver JDBC utiliser, deux mthodes : 1. compiler les sources avec la ligne :
% java -Djdbc.drivers=org.postgresql.Driver monfic.java

2. include dans le code :


Class.forName("org.postgresql.Driver");

Attention ! Le driver doit se trouver dans le CLASSPATH ; sil sagit dun chier jar, le chier lui mme doit tre dans le classpath :
export CLASSPATH=.:/home/titi/postgresql.jar:/usr/local/jdk1.2

3.4

tablir la connexion

On utilise :
Connection DriverManager.getConnection(String url, String login, String passwd);

La forme de lURL est :


jdbc:sous protocole:adresse

3.4.1 Exemple :
try { Connection db; String url= "jdbc:postgresql://localhost/guest"; db= DriverManager.getConnection(url, "guest", "toto"); // manipulations diverses : .... // on a fini : db.close(); } catch (SQLException e) { }

ladresse est ici compose du nom du serveur postgres (localhost) suivi du nom de la base de donne (ici, guest ; lIUT ce sera votre nom de login).

3.5. ENVOYER UNE REQUTE

77

3.5

Envoyer une requte


effectues par la mthode

les requtes sont reprsentes par la classe Statement ; les modications de la base sont Statement.executeUpdate(String) ;

les requtes sont effectues par la mthode Statement.executeQuery(String) ; Le rsultat dune requte Query est un ResultSet
// On cre un canal de communication Statement st= db.createStatement(); // On envoie une requte ResultSet res= st.executeQuery("select * from Etud"); // Tant quil y a des lignes dans le rsultat.. while (res.next()) { // on lit les valeurs des champs System.out.println("col 1 = " + rs.getString("Nom")); } res.close(); st.close();

Notes : on peut avoir plusieurs requtes ouvertes sur la mme connexion ; il nest possible daccder un champ quune fois et une seule ; il est ncessaire de fermer (close) les Statement et les ResultSet.

3.5.1 Mthodes
ResultSet executeQuery (String requete) throws SQLException Envoie une requte SQL, (normalement de type select ), et renvoie le rsultat sous forme dun ResultSet. Le rsultat nest jamais null. int executeUpdate (String requete) throws SQLException Excute une requte de modication des donnes ou de la base (bref, tout ce qui nest pas select). La valeur retourne normalement le nombre de lignes modies, ce qui a un sens pour insert, delete, update. Pour les autres oprateurs, le rsultat est 0.

78

CHAPITRE 3. JAVA ET LES BASES DE DONNES

boolean execute (String requete) throws SQLException Envoie une requte SQL qui peut mme envoyer plusieurs rsultats. Le rsultat est true si la premire valeur renvoye est un ResultSet. Nous dtaillons plus avant la mthode execute en 3.5.3.

3.5.2 Mthodes applicables un ResultSet


Les mthodes suivantes permettent daccder la valeur dune colonne, soit en passant comme argument le numro de colonne (commenant 1), soit le nom de la colonne : getByte getShort getInt getLong getFloat getDouble getBigDecimal getBoolean getString getBytes getDate getTime getTimestamp getAsciiStream getUnicodeStream getBinaryStream getObject Par ailleurs, aprs appel dune de ces mthodes, la mthode wasNull() permet de savoir si en fait la valeur tait NULL.

3.5.3 Execute
La mthode execute() permet denvoyer une requte, quelle soit de type select ou quelle soit une modication dune base. Les mthodes utilises dans lexemple suivant permettent de rcuprer des informations sur la requte. Bien entendu, dans la plupart des cas, le programmeur sait quelle est la requte, et donc utilise executeQuery ou executeUpdate(). La mthode execute() sera, par exemple, utilise dans un programme o lutilisateur pourra saisir une requte SQL quelconque.
Utilisation gnrale de Execute stmt.execute(queryStringWithUnknownResults); while(true) { int rowCount = stmt.getUpdateCount(); if(rowCount > 0) { // Des donnes ont t modifies System.out.println("Rows changed = " + count); stmt.getMoreResults(); continue; } if(rowCount == 0) { // Modification de la Structure, // ou pas de changement. System.out.println(" Pas de ligne modifie, ou la ligne est une commande DDL"); stmt.getMoreResults(); continue; } // Si on arrive ici, il sagit dune requte ResultSet rs = stmt.getResultSet; if(rs != null) { ... // Il faut utiliser les mtadata pour connatre // la liste des colonnes while(rs.next())

3.6. COMMANDES PRPARES


{ ... // Traiter le rsultat stmt.getMoreResults(); continue; } break; // there are no more results } }

79

3.6

Commandes prpares

classe PreparedStatement ; typiquement, commande utilise plusieurs fois en changeant la valeur de certains paramtres ; les paramtres qui changent sont remplacs dans la commande par des ? ; les commandes setXXX (o XXX est le type de la variable) permettent de spcier la valeur des paramtres.
PreparedStatement pstmt = connec.prepareStatement("UPDATE table4 SET m = ? WHERE x = ?"); ... pstmt.setString(1, "Hi"); for (int i = 0; i < 10; i++) { pstmt.setInt(2, i); int rowCount = pstmt.executeUpdate(); }

NULL : pour que la valeur dun paramtre soit NULL , il suft dutiliser la commande setNull

3.7
But :

chappements SQL
avoir une plus grande portabilit, et faciliter la cration de commandes SQL. Dans la chane de commande SQL :

Syntaxe :

{commande arguments}

80

CHAPITRE 3. JAVA ET LES BASES DE DONNES

Spcier un caractre dchappement :


stmt.executeQuery("SELECT name FROM Identifiers WHERE Id LIKE \_% {escape \}");

Spcier une date :


{d yyyy-mm-dd}

3.8

Gestion des transactions

par dfaut, chaque requte forme une transaction ; pour changer ce comportement, on manipule lobjet Connection li la base de donne:
maconnexion.setAutoCommit(false);

ensuite : maconnexion.commit(); valide les requtes dj effectues lors de cette transaction ; maconnexion.rollback(); annule les requtes dj effectues ;

3.8.1 Niveau disolement


But : une transaction doit voir un tat de la base. Dans le cas daccs concurrents la base : on peut changer le type daccs concurrent avec la mthode de Connection :
public void {setTransactionIsolation}(int level) throws SQLException

o level peut valoir : TRANSACTION_READ_UNCOMMITTED TRANSACTION_READ_COMMITTED TRANSACTION_REPEATABLE_READ TRANSACTION_SERIALIZABLE TRANSACTION_READ_UNCOMMITTED on peut lire des modications ds quelles sont faites. En cas de ROLLBACK, postrieur, les valeurs lues peuvent tre fausses ; TRANSACTION_READ_COMMITTED on ne peut pas lire une range sur laquelle il y a des modications non valides (par commit) ;

3.9. CAPACITS DE LA BASE DE DONNES : DATABASEMETADATA

81

TRANSACTION_REPEATABLE_READ idem ; de plus, vite le cas o la transaction lit une range, une autre transaction la modie, et la premire relit la range modie ; la lecture donne toujours le mme rsultat, do le nom ; TRANSACTION_SERIALIZABLE le comportement est similaire celui obtenu avec un traitement squentiel. Empche le cas o 1. la transaction fait un select avec une condition ; 2. une seconde transaction cre des lignes qui satisfont la condition ; 3. la premire transaction refait le mme select.

3.9

Capacits de la base de donnes : DataBaseMetaData

Se rcupre grce la mthode getMetaData() de Connection les mthodes permettent de connatre les capacits de la base. Par exemple : supportsSelectForUpdate() renvoie vrai si la base permet dutiliser un select dans un update (cf. le cours de SQL !) des mthodes permettent dobtenir le catalogue de la base et la liste des tables : ResultSet getTables (String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException revoie un ResultSet dcrivant les tables et les index de la base. Par exemple, pour afcher la liste des tables et index :
rs= meta.getTables(null , null, null, null); while (rs.next()) { System.out.println(rs.getString("TABLE_NAME"); } rs.close();

Les arguments de getTables peuvent tre nuls. Les plus intressants sont : types : un tableau de chanes de caractre, donnant le type des tables rcuprer, entre autres : TABLE pour les tables stricto sensu, VIEW pour les vues.

3.10

Exploration des tables

la mthode getMetaData() de linterface ResultSet permet de rcuprer le ResultSetMetaData associ.

82

CHAPITRE 3. JAVA ET LES BASES DE DONNES

3.10.1 mthodes de ResultSetMetaData


int getColumnCount() nombre de colonnes ; String getColumnName(int column) : nom de la i e colonne ; String getColumnLabel(int column) : titre de la colonne pour afchage ; int getColumnType(int column) : type SQL de la colonne ; les valeurs possibles pour le rsultat sont dcrites dans java.sql.Types.

3.11

Extensions du jdbc2.0

La version 2.0 du jdbc propose un certain nombre dextensions.

3.11.1 ResultSet navigables


Par dfaut, on ne peut parcourir un un ResultSet que dune manire : du premier au dernier lment. Le jdbc version 2 permet de se dplacer librement dans un ResultSet, et ventuellement den modier les lments. Ces options ne sont pas forcment implmentes par les drivers jdbc. Par exemple, le driver postgresql permet les dplacements, mais pas la modication. Pour disposer de ResultSets modiables, il faut le demander au moment de crer un Statement, en utilisant la mthode createStatement de la classe Connection : Statement createStatement (int resultSetType, int resultSetConcurrency) throws SQLException resultSetType trois valeurs possibles : ResultSet.TYPE_FORWARD_ONLY : seul les dplacements vers lavant sont possibles ResultSet.TYPE_SCROLL_INSENSITIVE : tout dplacement est possible. Par contre, si les donnes sont modies, et que lon revient sur une ligne dj visite, la valeur visible sera la valeur dorigine et non la valeur modie. ResultSet.TYPE_SCROLL_SENSITIVE : tout dplacement est possible. , Si les donnes sont modies, et que lon revient sur une ligne dj visite, la valeur visible sera la valeur modie. resultSetConcurrency : rgle le comportement du ResultSet en cas par raport aux transactions. ResultSet.CONCUR_READ_ONLY : lecture seule ; ResultSet.CONCUR_UPDATABLE : modiable.

3.11. EXTENSIONS DU JDBC2.0


Dplacement dans le ResultSet

83

Un ResultSet fonctionne comme un tableau dont les cases sont numrotes de 1 n. Il dispose de plus de deux positions spciales, beforeFirst et afterLast, aux deux extrmites du tableau. Le curseur est lorigine plac sur beforeFirst. void last () throws SQLException se place au dernier enregistrement.

void first ()

throws SQLException se place au premier enregistrement. throws SQLException se place aprs le dernier enregistrement.

void afterLast ()

void beforeFirst ()

throws SQLException se place avant le premier enregistrement.

void next ()

throws SQLException avance lenregistrement suivant. throws SQLException avance lenregistrement prcdent.

void previous ()

boolean absolute (int i) throws SQLException se place sur lenregistrement numro i. Si i vaut 1, cest lquivalent de first. Si i est ngatif, on numrote partir du dernier enregistrement. La fonction renvoie true si le curseur pointe sur un enregistrement valide. boolean relative (int delta) throws SQLException Dplacement relatif la position courante. relative(-1) est quivalent previous, et relative(1) next(). La fonction renvoie true si le curseur pointe sur un enregistrement valide. int getRow () throws SQLException renvoie lindice de la ligne courante.

84 Modication dun ResultSet

CHAPITRE 3. JAVA ET LES BASES DE DONNES

Un ResultSet nest modiable que si on la demand et que le driver le gre. Les mthodes principales sont (remplacer XXX par int, String...) : void updateXXX (int i, XXX a) throws SQLException e champ, de type XXX, en lui donnant la valeur a. modie le i void updateXXX (String name, XXX a) throws SQLException modie le champ nomm name, de type XXX, en lui donnant la valeur a. void deleteRow () throws SQLException dtruit la ligne courante.

void moveToInsertRow () throws SQLException se place sur une ligne spciale, qui sert aux insertions de nouvelles donnes. void moveToCurrentRow () throws SQLException aprs un appel moveToInsertRow, revient sa position initiale. void insertRow () throws SQLException insre le contenu de la ligne dinsertion dans la base.

85

Chapitre 4 Java Server Pages et Servlets


On trouvera un rpertoire dexemples ladresse : http://www.iut.univ-paris8.fr/~rosmord/DOCS/demojsp.tgz Ces exemples sont conus et tests avec tomcat4, sous debian. Pour pouvoir les essayer : 1. allez dans rpertoire testTomcat ; 2. lancez le script : ./tom start ; 3. attendez un peu ; 4. connectez-vous ladresse http://localhost:9180/index.html

4.1

Architecture dune application web

Rappel sur notions de client et serveur ; javascript et les applets java sexcutent sur le client ; au contraire, les applications cgi, les scripts php, les jsp et les servlets sexcutent sur le serveur. Exemple dun script php : le client demande une page, qui est en fait un script php. Le serveur excute le script, dont le rsultat (typiquement une page html) est expdi comme rponse, puis visualis par le client.

4.2

Introduction aux jsp

4.2.1 principes
Le principe dune jsp est similaire celui dun script php. Il sagit de texte html mlang du code, crit en java dans le cas des jsp.

86

CHAPITRE 4. JAVA SERVER PAGES ET SERVLETS

Une page jsp est traite par le serveur (tomcat par exemple), qui cre le code dune classe java associe. Par exemple, pour une page jsp nomme test.jsp, tomcat cre une classe test$jsp.java. chaque page jsp correspond donc une classe java. Le code html et une partie du code jsp proprement dit sont utiliss par le serveur pour produire la mthode _jspService, qui est appele lexcution de la jsp pour crer la page rsultat.

4.2.2 Balises principales des jsp


<% %> : cette balise encadre des instructions java qui feront partie de la mthode _jspService utilise pour produire la page rsultat :
<html><body> bonjour, voici la valeur de 3 + 4 : <% // du code java int x= 3 + 4; out.write("" + x); %> </body></html>

<%= %> : cette balise encadre une expression java. La valeur de cette expression sera afche dans la page rsultat :
<html><body> bonjour, voici la valeur de 3 + 4 : <%= 3 + 4 %> </body></html>

<%! %> : cette balise permet dajouter des mthodes et des champs la classe qui correspond la jsp. <%@ page ... %> : la balise directive de page sert congurer un certain nombre doptions pour la jsp. Parmis celles-ci, citons : <%@ page import="..." %> permet de raliser dimporter des packages java, comme par exemple :
<%@ page import="java.sql.*" %>

<%@ page include="toto.jsp" %> : inclut le chier toto.jsp. <%@ page errorPage="toto.jsp" %> : en cas de leve dexception sur cette page, on afchera toto.jsp. La variable exception contiendra lobjet exception correspondant. <%@ page isErrorPage="true" %> : signie que cette page est une page de traitement dexception (voir directive prcdente).

4.3. INTRODUCTION AUX SERVLETS

87

4.2.3 Les champs dune jsp


Dans une jsp, les variables suivantes sont dnies : out : un objet de classe JspWriter (qui descend de PrintWriter). Permet dcrire dans le rsultat. Les mthodes print et println sont dnies pour les principaux types de bases. request : objet de type HttpServletRequest, qui reprsente la requte qui a amen sur cette page. Deux mthodes sont particulirement utiles : getParameter(String name) qui renvoie la valeur dun paramtre (un champ dun formulaire html). Pour les champs multi-valus, on peut utiliser getParameterValues(String name). response : page session : application cong pageContext

4.2.4 Installation des jsp


Les jsp doivent se trouver dans des sous-rpertoires (ou en-dessous) du rpertoire webapps ; leur nom doit se terminer par le sufxe jsp.

4.3

Introduction aux servlets

4.3.1 principe des servlets


Une servlet est une classe java. La requte (provenant gnralement dun formulaire) est traite par la mthode doPost ou par la mthode doGet de la servlet, selon le type de requte. La servlet construira ensuite la rponse, en manipulant un objet de classe HttpServletResponse.

4.3.2 Installation des servlets


Linstallation des servlets est plus complexe que celle des jsp. Il nous faut donc dtailler plus prcisment le rpertoire webapps. Ce rpertoire contient des sous-rpertoire, chacun deux tant une application web. Chaque sous-rpertoire peut contenir un nombre quelconque de

88

CHAPITRE 4. JAVA SERVER PAGES ET SERVLETS

jsp et de servlets. Si vous regardez le contenu de test1, vous constaterez que rien nindique a priori quil contient une servlet :
bash-2.05a$ pwd /home/rosmord/Prog/testTomCat/webapps bash-2.05a$ ls -R test1 test1: index.html WEB-INF test1/WEB-INF: classes web.xml test1/WEB-INF/classes: TestServlet.class bash-2.05a$

Cependant, il en existe bien une, accessible ladresse : http://localhost:9180/test1/salut. En fait, les servlets sont contenues dans le rpertoire WEB-INF. Ce rpertoire contient : un chier web.xml, qui permet de congurer les servlets et en particulier de les associer une URL ; un rpertoire classes, qui contient des classes java (et ventuellement des packages) ; un rpertoire lib, qui contient des archives jar (par exemple, les bibliothques ncessaires pour jdbc). Quand une servlet est crite, il faut la compiler, et placer le rsultat dans le rpertoire classes. Les commandes suivantes peuvent convenir :
export CLASSPATH CLASSPATH=/usr/share/java/servlet-2.3.jar javac Hello.java mv Hello.class testTomCat/webapps/appli1/WEB-INF/classes/

Il reste cependant prciser comment on lance la servlet. Cest le travail du chier web.xml. Pour chaque servlet, il contient deux informations : la classe associe la servlet ; lurl associe la servlet. Ainsi, le chier suivant permet de prciser que la servlet bonjour est associe lurl hello et la classe TestServlet . vitez dutiliser des accents ou autres caractres non ascii 1 .
<?xml version="1.0" ?> <!DOCTYPE web-app web.xml

1. ou prcisez <?xml version="1.0" encoding="iso-8859-1"?> en en-tte.

4.3. INTRODUCTION AUX SERVLETS


PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"

89

> <!-- les formules magiques ci-dessus sont a reprendre telles quelles :-) --> <!-- Le corps du fichier est compris dans la balise web-app : --> <web-app> <!-- la balise servlet lie la servlet a la classe qui limplemente. --> <servlet> <servlet-name>bonjour</servlet-name> <servlet-class>monPackage.TestServlet</servlet-class> </servlet> <!-- lie la servlet a une url --> <servlet-mapping> <servlet-name>bonjour</servlet-name> <url-pattern>/salut</url-pattern> </servlet-mapping> </web-app>

4.3.3 Les servlets, leur vie, leur uvre


La base du fonctionnement des servlets est que lune des deux mthodes doGet et doPost est appele pour traiter la requte du serveur. Il est important de comprendre que lobjet servlet nest pas dtruit aprs une requte : il sera rutilis pour les consultations ultrieures de la mme servlet. la premire consultation dune servlet, le serveur cre un objet de la classe considre ; il rutilisera cet objet lors des consultations ultrieures de la servlet. Une fois lobjet cr, la mthode init est appele pour linitialiser. init nest appele quune seule fois dans la vie de la servlet. Ensuite, selon la requte, la mthode doGet ou doPost est appele. Ces deux mthodes sont trs similaires, et prennent les mmes arguments : public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException request reprsente la requte envoye la servlet. Utilis pour accder aux paramtres de celles-ci. response permet de construire la rponse la requte. Voici un exemple simple de compteur en mmoire :
import java.io.*; import javax.servlet.*; TestServlet.java

90
import javax.servlet.http.*;

CHAPITRE 4. JAVA SERVER PAGES ET SERVLETS

public class TestServlet extends HttpServlet { int valeur; public void init() throws ServletException { super.init(); valeur=0; } public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { valeur++; // On prcise que le rsultat est une page de texte simple : // (pour du html, ce serait : text/html) httpServletResponse.setContentType("text/plain"); // out permettra dcrire ce rsultat : Writer out= httpServletResponse.getWriter(); // On cre la page. out.write("valeur du compteur : "+ valeur); } }

La dernire mthode importante est destroy, qui est appele lors de la destruction de la servlet. Attention ! une servlet peut tre dtruite quand le serveur le juge opportun. Il ne faut donc pas compter sur la conservation des donnes en mmoire entre deux appels de servlets.

4.4

Les javabeans

Les protocoles web classiques ne grent pas de session. Typiquement, un utilisateur demande une page web au serveur, et celui-ci la renvoie. Il nest pas prvu initialement de conserver sur le serveur des informations sur lutilisateur, comme un mot de passe utilis pour interroger une base de donnes, ou une corbeille (liste de produits commands. Il existe plusieurs mthodes pour contourner ces difcults. Larchitecture JSP/Servlets propose une solution simple et lgante, les javabeans. Un javabean est un objet java, identi par un nom (une chane de caractres), dont la dure de vie peut dpasser la simple requte http. Les beans sont utilisables partir des jsp

4.4.1 Les classes de beans


Pour quun objet java puisse tre utilis comme bean, les conditions sont trs simples :

4.4. LES JAVABEANS


Sa classe doit : implmenter java.io.Serializable ; disposer dun constructeur par dfaut (i.e. sans argument) ;

91

avoir des accesseurs (imprativement nomms setXX et getXX, o XX est le nom dun champ. la classe doit tre explicitement situe dans un package. La classe suivante prsente un bean trs simple :
package test; Le bean Compteur

public class Compteur implements java.io.Serializable { private int valeur; public Compteur(int v) { valeur= v; } public Compteur() { valeur= 0; } public void incremente() { valeur++; } public int getValeur() { return this.valeur; } public void setValeur(int argValeur) { this.valeur = argValeur; } }

4.4.2 Accs aux beans depuis les jsp


La jsp qui suit montre une utilisation possible dun bean :
testBean.jsp <!doctype html PUBLIC -//W3C//DTD HTML 3.2//EN> <html> <head> <title>test Beans 1</title> </head> <body> <!-- dclaration du bean -->

92

CHAPITRE 4. JAVA SERVER PAGES ET SERVLETS


<jsp:useBean id="cpt" scope="application" class="test.Compteur"/> <!-- utilisation du bean --> Le compteur vaut : <jsp:getProperty name="cpt" property="valeur"/> Quand on fixe la valeur, on utilise en plus lattribut <tt>param</tt>. <% // Utilisation du bean par du code java : cpt.incremente();

%> </body> </html>

Les balises spciques au beans sont : <jsp:useBean ... /> permet de dclarer un bean et de lui donner un nom et une dure de vie. Lobjet correspondant est cr sil nexiste pas, et rutilis sil existe dj. Les attributs remplir sont : id : Le nom donn au bean. Ce nom permet de lidentier et de le rcuprer. Par ailleurs, le bean est accessible dans le code java de la jsp travers une variable qui a le nom indiqu. Do le code
<% cpt.incremente(); %>

Dans notre exemple. scope : dure de vie du bean. Peut tre xe page, request, session ou application. En pratique, les deux derniers sont les plus intressants. Loption session dsigne une session de travail de lutilisateur. La session commence la connexion, et se termine quand lutilisateur arrte son navigateur, ou aprs un temps dinactivit paramtrable (xable par la mthode setMaxInactiveInterval(int interval) de la classe HttpSession ; cette mthode prend comme argument une dure en secondes). Chaque utilisateur connect aura sa propre version dun bean session. Loption application signie que le bean existe pour toute la dure de vie du serveur tomcat ; le bean est alors unique pour tous les utilisateurs. class : la classe utilise pour implmenter le bean. Le nom de la classe doit tre de la forme nompackage.NomClasse. <jsp:getProperty ... /> cette balise sera remplace dans la page HTML rsultat par la valeur dun des attributs du bean. Les attributs remplir sont : name : nom du bean (celui dni prcdemment par id="..." ;

4.4. LES JAVABEANS

93

property : nom de la proprit, qui doit tre un des champs dnis par le bean. Pour que cela fonctionne, la classe bean doit disposer daccesseurs correspondant au mme nom. <jsp:setProperty ... /> permet de xer la valeur dun champ du bean. Les attributs sont : name : nom du bean ; property : nom du champ ; value : valeur donner au champ.

4.4.3 accs aux beans depuis les servlets


Il est aussi possible de crer et de lire des beans depuis des servlets. La procdure diffre selon la porte (scope) du bean. session On doit procder en deux temps. Il faut dabord rcuprer un objet de classe HttpSession :
HttpSession session= request.getSession(true);

On peut ensuite rcuprer ou donner une valeur dun bean en utilisant : les mthodes getValue et putValue dans la version 3 de tomcat ; les mthodes getAttribute et setAttribute dans la version 4. Seul le nom des mthodes change. Leur utilisation est la mme. void setAttribute (String nomBean, Object bean) cre un nouveau bean :
session.setAttribute("cpt", new Compteur());

Object getAttribute (String nomBean) rcupre lobjet bean associ un nom. Par exemple :
Compteur c= (Compteur)session.getAttribute("cpt"); c.incremente(); // ...

application La mthode getServletContext() de la classe GenericServlet (dont hrite toute servlet) renvoie un objet de classe ServletContext, qui reprsente lapplication. Cet objet dispose lui aussi de mthodes setAttribute et getAttribute.

94

CHAPITRE 4. JAVA SERVER PAGES ET SERVLETS

4.5

Architecture typique dune application jsp

Pour avoir le code le plus propre possible, on utilise servlets et jsp uniquement dans la couche interface utilisateur. Pour le reste de lapplication, on utilise des classes java normales, typiquement spares en plusieurs couches : logique applicative, modle, persistence. De plus, on utilise les jsp uniquement pour les afchages 2 . Le traitement des requtes est quant lui con des servlets.

4.5.1 Redirection vers une jsp


Quand une servlet sest excute, il faut bien videmment prciser ce qui doit safcher sur le navigateur du client. Il est possible quune servlet fasse traiter ses afchage par une jsp. Pour cela, elle utilise un objet de classe RequestDispatcher :
String url= "adresse de la jsp afficher"; // On cre le dispatcher en prcisant lurl cible. RequestDispatcher dispatcher= getServletContext().getRequestDispatcher(url); // on redirige la requte courante. Notez que les paramtres de // doGet() ou doPost() sont transmis la jsp : dispatcher.forward(request, response);

Il existe aussi une mthode sendRedirect, demploi plus simple. Cependant, cette dernire est beaucoup moins efcace, car elle demande au client de procder une redirection. Gnralement, la servlet a trait la requte, et a modi ou cr des donnes. La jsp vers laquelle on redirige le traitement aura souvent pour fonction dafcher le rsultat de ces traitements. Ces donnes doivent donc tre passes la jsp. On pourrait le faire par lintermdiaire de javabeans, mais pour viter de charger le serveur, la meilleure manire est de dajouter ces donne dans le champ request, en utilisant la mthode setAttribute de la classe ServletRequest : void setAttribute (java.lang.String name, java.lang.Object o) Stocke o sous le nom name dans la requte. Si o est null, alors lattribut est supprim dans la requte.
String url= "adresse de la jsp afficher"; RequestDispatcher dispatcher= getServletContext().getRequestDispatcher(url); dispatcher.forward(request, response);

4.6

Le suivi des sessions

La gestion des sessions seffectue en utilisant souvent les cookies. Cependant, les utilisateurs ne les acceptent pas toujours. Il existe une autre manire pour grer les numros de session, cest
2. Notez que rien ninterdit de coner lafchage des servlets. Cependant, les spcialistes de design web ntant gnralement pas des programmeurs, on prfrera les jsp pour la prsentation.

4.6. LE SUIVI DES SESSIONS

95

de le passer comme paramtre dune requte lautre, en le codant dans les url. Il est possible de faire automatiquement grer les deux modes par le serveur. Pour cela, les url doivent tre spcies en utilisant la mthode encodeURL de la classe HttpServletResponse.
<begin> Page <a href="<%= response.encodeURL("next.jsp") %>">suivante</a>. <end>

Quand lutilisateur accepte les cookies, le numro de session sera stock comme un cookie, et lURL sera next.jsp . Quand il les refuse, le numro de session sera inclus dans lURL :
URL gnre par encodeURL() next.jsp;jsessionid=FAC06A1658A6C485294302CD336BA48F

96

CHAPITRE 4. JAVA SERVER PAGES ET SERVLETS

4.7

Cration de nouvelles balises pour les jsp

Pour simplier la vie des programmeurs de page web, et leur cacher autant que possible la couche java, il est possible de crer de nouvelles balises. Le code excut par ces balises sera dni dans des classes java. De telles bibliothqyes de balises (taglibs) sont disponibles sur le web. Voir par exemple : http://jakarta.apache.org/taglibs. On cre pour cela une bibliothque de tags, dont l

4.7.1 Une balise simple 4.7.2 Une boucle 4.7.3 Partage de variables

4.8

Quelques patterns

97

Chapitre 5 Java et XML


5.1 Le langage XML

5.1.1 Introduction
pourquoi XML : format gnrique de textes structurs. Les chiers complexes en format texte (exemple : sources povray, java...) ne sont pas facile analyser. Il faut gnralement dcrire le format laide dune grammaire, puis crire un programme en consquence. Cela demande une certaine exprience. XML est (relativement) simple ; de plus le mme code peut analyser nimporte quel document XML. historique de xml : sgml, html. XML descend de SGML (structured generic markup language), utilis au dpart pour crire des documentations techniques. domaines demplois de xml. 1. format de sauvegarde et dchange portable. Les dernires versions de word utilisent XML, de mme quOpenoffice. Noter que les documents Openoffice sont sauvegards sous la forme dun chier zipp contenant plusieurs documents XML. ; 2. format de documents smantiques. Les documents XML sont lisibles et manipulables par les navigateurs web rcents. 3. base de donnes XML.

5.1.2 Documents XML


documents bien forms Un document xml doit imprativement respecter les rgles suivantes : il est sauvegard en codage UTF-8 (ou 16), sauf indication contraire. Notez quun document sauv en vrai ASCII (7 bits) satisfait cette condition, puisque UTF-8 concide avec lASCII pour les codes de 0 127.

98 il commence par une en-tte de la forme :


<?xml version="1.0"?>

CHAPITRE 5. JAVA ET XML

le corps du document est plac entre une balise ouvrante et une balise fermante ; les balises (tags) sont toujours groupes par deux : une balise ouvrante (<Nom>) et la balise fermante (</Nom>) correspondante. ces balises sont correctement parenthses. On ne doit pas les croiser. Par exemple : <A><B>du texte</A></B> est incorrect. On devrait avoir <A><B>du texte</B></A>. Lorsque le contenu dune balise est toujours vide, la balise ouvrante est aussi fermante. En xml, le tag IMG de html se coderait :
<img src="...."/>

les valeurs des attributs sont toujours indiques entre guillemets. Quand un document est cod dans un code diffrent de lUTF-8, il doit le prciser dans son en-tte. Attention, cette rgle est vraie mme si les caractres non UTF-8 napparaissent que dans des commentaires. Ainsi,
<?xml version="1.0" encoding="iso-8859-1"?>

dclare que le document est cod en iso-8859-1, le codage standard sous Unix.
Exemple de document XML <?xml version="1.0" encoding="iso-8859-1"?> <promotion id="premire anne info"> <etudiant id="1"> <nom>Turing</nom> <prenom>Alan</prenom> <passe/> </etudiant> <etudiant id="2"> <nom>Lovelace</nom> <prenom>Ada</prenom> <passe/> </etudiant> </promotion>

Document Type Denition (DTD) Une DTD dcrit la structure que peut avoir un type de document XML. Il existe de nombreuses dtd dj faites, et il est possible (et relativement ais) den crer de nouvelles. Au lieu de rinventer la poudre, on aura cependant intrt rutiliser tout ou partie de DTD existantes.

5.1. LE LANGAGE XML

99

La DTD suivante dcrit un format (trs simpli) utilisable pour un livre. Celui-ci est constitu dune suite non vide de chapitre, chacun de ceux-ci tant form dun titre, dun contenu, et dun commentaire optionnel.
<!ELEMENT <!ELEMENT <!ELEMENT <!ELEMENT <!ELEMENT <!ATTLIST livre (chapitre)+> chapitre titre contenu commentaire commentaire id type auteur livre.dtd

(titre,contenu,commentaire?)> (#PCDATA)> (#PCDATA)> (#PCDATA)>

ID (accord|desaccord) CDATA

#IMPLIED "desaccord" #IMPLIED >

Une DTD dcrit, entre autres, les lments qui composent un document (les balises), les attributs que ceux-ci peuvent avoir, ainsi quun certain nombre de Dclaration des lments La dclaration des lments est la partie la plus complexe de la DTD. Elle a la forme :
<!ELEMENT nomElement (DescriptionElement)>

o : nomElement est le nom de llment (attention, XML est sensible la casse du texte) ; descriptionElement explique ce que peut contenir llment en utilisant un langage spcial. Pour dcrire les lments de ce langage, prenons comme convention que tout groupe en caractres obliques correspond une construction de la liste.

nomElement : un autre lment ; A,B : la squence A, B puis C ; A |B : A ou B. ; A * : A rpt 0 ou plusieurs fois ; A + : A rpt 1 ou plusieurs fois ; A ? : optionellement A ;
#PCDATA : du texte analys. Ainsi, la dclaration :
<!ELEMENT section (titre, auteur?, (paragraphe|image)*)>

100

CHAPITRE 5. JAVA ET XML

indique quun lment section est compos dun lment titre, suivi optionellement dun lment auteur, suivi dune suite ventuellement vide de paragraphes et/ou dimages. Quand un lment peut contenir directement du texte, il y a quelques contraintes : #PCDATA doit apparatre en premier dans la description de son contenu ; si le #PCDATA nest pas seul, la description a forcment la forme :
<!ELEMENT nomElement (#PCDATA|nomElt1|nomElt2|...)*>

par exemple, voici deux dclarations possibles :


<!-- un titre est simplement compos de texte --> <!ELEMENT titre (#PCDATA)> <!-- un paragraphe peut contenir du texte et des notes de bas de page --> <!ELEMENT paragraphe (#PCDATA|note)*>

Le bout de texte suivant est valide par rapport la dnition propose :


<section><titre>Le langage XML</titre> <paragraphe> Voici du texte<note>et une note</note> et encore du texte. </paragraphe> <paragraphe> Un second paragraphe</paragraphe> <image source="toto.jpg"/> <paragraphe> Un troisime paragraphe</paragraphe> </section>

Dans certains cas, un lment peut ne pas avoir de contenu. On le dclare alors :
<!ELEMENT nomElement EMPTY>

Par exemple :
<!ELEMENT image EMPTY>

Dclaration des attributs Les attributs dun lment sont dclars de la manire suivante :
<!ATTLIST NomElement NomAttribut1 TypeAttribut1 DefautAttribut1 NomAttribut2 TypeAttribut2 DefautAttribut2 ... >

o NomElement est le nom de llment dont on dclare les attributs, NomAttribut1 est un nom dattribut. TypeAttribut1 peut avoir plusieurs valeurs diffrentes, notamment

CDATA : lattribut a comme valeur une chane de caractres quelconque ;

5.1. LE LANGAGE XML

101

une liste de la forme (A|B|...) : A,B... sont les diffrentes valeurs possibles. Exemple :
<!ATTLIST rendezVous jour (lundi|mardi|mercredi|jeudi|vendredi|samedi|dimanche) #REQUIRED>

ID : un identicateur. Quand on lutilisera dans un document la valeur utilise devra tre unique. IDREF : rfrence un identicateur dans le mme document. NMTOKEN : un nom XML bien form (une suite de lettres, de chiffres, de soulign (_ ), de : ).
DefautAttribut1 prcise si la valeur de lattribut est ncessaire ou non, et ventuellement si celui-ci a une valeur par dfaut. La chane peut tre :

Valeur par dfaut : une valeur par dfaut pour lattribut ; #REQUIRED : lattribut est ncessaire ; #IMPLIED : lattribut est optionnel.
documents valides

Un document xml est dit valide sil est bien form et quil respecte une DTD.

5.1.3 XSLT
Documentation : http://www.w3.org/TR/1999/REC-xslt-19991116. Le langage XSLT (XML Stylesheet Transformation) permet de crer un document XML, HTML ou texte partir dun document XML dorigine. Par rapport au systme CSS1 (feuilles de styles HTML), XSLT a lavantage de pouvoir modier la structure du document auquel il est appliqu. Une feuille de style XSLT est un document xml. Elle contient des rgles de formatage qui sappliquent aux diffrentes parties dun documents. La feuille XSL ci-dessous permet de produire un document html avec une la table des matires.
doc.xsl <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output method="html"/> <!--

102

CHAPITRE 5. JAVA ET XML


rgle appliquer au document dans son ensemble : on commence par gnrer len-tte, puis une table des matires, puis on met en forme le corps du document -->

<xsl:template match="mondocument"> <html> <header> </header> <body> <!-- la table des matires --> <ul> <xsl:for-each select="chapitre/titre"> <li> <a href="#{generate-id(..)}"> <xsl:number count="chapitre"/><xsl:text>. </xsl:text> <xsl:value-of select="."/> </a> </li> </xsl:for-each> </ul> <!-- le corps du document --> <xsl:apply-templates/> </body> </html> </xsl:template> <!-- On transforme les titres en titres html, en crant un identificateur pour la table des matires --> <xsl:template match="titre"> <h1><a name="{generate-id(..)}"> <xsl:number count="chapitre"/> <xsl:text>. </xsl:text> <xsl:apply-templates/> </a> </h1> </xsl:template> <!-- Les commentaires ne sont pas affichs : --> <!-- Sans cette rgle, leur texte serait recopi tel quel. --> <xsl:template match="commentaire"> </xsl:template> </xsl:stylesheet>

Pour lappliquer, on peut placer la dclaration


<?xml-stylesheet href="doc.xsl" type="text/xsl"?>

dans le document xml mettre en forme. Les navigateurs webs rcents reconnatrons ce type de dclaration. Java permet dappliquer une feuille de style XSL un document quelconque.

5.2. LES API JAVA

103

5.1.4 Schmas XML

5.2

Les API Java

DOM et SAX sont des spcications dAPI pour manipuler des documents XML. Selon le type de documents, et les manipulations souhaites, lune peut tre prfrable lautre.

5.2.1 Document object model (DOM)


DOM est base sur le principe que le document XML est analys pour construire une structure de donnes arborescente qui le reprsente. DOM spcie les structures utilises en termes de classes. Comme une application qui utilise DOM construit une reprsentation complte du document XML, elle est bien adapte quand il est ncessaire de naviguer dans ce dernier. Par contre, si le document est de grande taille, le modus operandi de DOM implique quil sera intgralement charg. Les tapes de lutilisation de DOM en java sont :

1. obtenir (et congurer) un analyseur DOM ; 2. lappliquer au document ; 3. parcourir/manipuler le document.


Obtention et appel dun analyseur DOM.

Il suft de procder comme ci-dessous.


DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); DocumentBuilder builder= factory.newDocumentBuilder(); Document doc= builder.parse("exemple1.xml");

La variable doc contient alors le document analys.


Manipulation dun document DOM.

La plupart des interfaces qui dcrivent une partie dun chier xml analys par DOM descendent de linterface org.w3c.dom.Node. Ces interfaces dnissent des mthodes en lecture et en criture. Cest--dire quil est possible de modier un document en mmoire (la classe Transformer permet ensuite ventuellement de sauver ce document). Ces interfaces sont principalement : Attr, Comment, Document, Element, Text. Tout texte balis est reprsent par un Element, y compris le document dans son ensemble. Cependant, celui-ci est inclus dans un Node de type Document.

104

CHAPITRE 5. JAVA ET XML

Comme toutes ces interfaces descendent de Node, le mieux est de considrer les mthodes de cette interface.
Node appendChild (Node newChild) ajoute un ls ce nud NamedNodeMap getAttributes () rcupre les attributs de ce nud. Ne fonctionne que sur un Element (renvoie null pour les autres nuds). NodeList getChildNodes () rcupre la liste des enfants de ce nud. Node getNextSibling () le frre de ce nud String getNodeName () le nom de ce nud short getNodeType () le type de ce nud, parmis ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE PROCESSING_INSTRUCTION_NODE TEXT_NODE ( faire prcder de Node.). String getNodeValue () la valeur de ce nud Node getParentNode () le pre de ce nud boolean hasAttributes () retourne vrai si ce nud a des attributs boolean hasChildNodes () retourne vrai si ce nud a des enfants Node insertBefore (Node newChild, Node refChild) insre newChild avant refChild Node removeChild (Node oldChild) supprime oldChild void setNodeValue (String nodeValue) The value of this node, depending on its type; see the table above.

5.2. LES API JAVA


Mthodes des classes NodeList et NamedNodeMap int getLength () rcupre le nombre de nuds dans la liste. Node item (int i) rcupre le ie nuds dans la liste Mthodes de la classe Document Element getDocumentElement () rcupre llment racine du document. Mthodes de la classe Element String getAttribute (String name) renvoie la valeur de lattribut name Attr getAttributeNode (String name) renvoie lattribut name String getTagName () Nom de llment. Mthodes de la classe Attr String getName () renvoie le nom de lattribut String getValue () renvoie la valeur de lattribut Mthodes de la classe Text String getData () rcupre le texte associ cet lment. Exemple
import import import import import import import

105

TestDOM.java javax.xml.parsers.DocumentBuilder; javax.xml.parsers.DocumentBuilderFactory; org.w3c.dom.Document; org.w3c.dom.Element; org.w3c.dom.Node; org.w3c.dom.NodeList; org.w3c.dom.Text;

106

CHAPITRE 5. JAVA ET XML

// Lit un document et laffiche de manire indente. public class TestDOM { // Utilis pour indenter laffichage. int profondeur= 0; private void dumpNode(Node node) { switch (node.getNodeType()) { case Node.ELEMENT_NODE : dumpElement((Element) node); break; case Node.TEXT_NODE : dumpText((Text) node); break; default : } } private void printSpaces() { for (int i= 0; i < profondeur; i++) System.out.print(" "); } private void print(String s) { System.out.print(s); } private void dumpElement(Element elt) { printSpaces(); print(elt.getNodeName()+ ":"); NodeList l= elt.getChildNodes(); profondeur++; for(int i= 0; i < l.getLength(); i++) { dumpNode(l.item(i)); } profondeur--; } private void dumpText(Text txt) { printSpaces(); print(txt.getData()); } public void dumpDocument(Document doc) { dumpElement(doc.getDocumentElement()); } public static void main(String[] args) throws Exception { TestDOM nav= new TestDOM(); DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); DocumentBuilder builder= factory.newDocumentBuilder();

5.2. LES API JAVA


Document doc= builder.parse("exemple1.xml"); nav.dumpDocument(doc);

107

5.2.2 Simple API for Xml Parsing (SAX)


SAX fonctionne selon les principes du design pattern builder . Une mthode est appele Pour chaque lment du document XML. SAX ne construit aucune structure ; il est donc bien adapt des parcours simples dun document. Par contre, la construction de structures volues est assez complexe (et rclame typiquement lutilisation dune pile). Les tapes de lutilisation de SAX en java sont :

1. cration dun analyseur SAX ; 2. cration dun builder pour le document (en tendant la classe DefaultHandler 1 .) ; 3. appel de lanalyseur sur le document.
Cration dun analyseur SAX

La cration de lanalyseur se fait aussi en deux tapes :


// Construction dun crateur danalyseur SAXParserFactory factory= SAXParserFactory.newInstance(); // Configuration. Ici on demande un analyseur non validant. factory.setValidating(false); // cration de lanalyseur SAXParser parser= factory.newSAXParser();

Cration dun builder pour le document

On doit crire une classe dont les mthodes seront appeles pour traiter les divers lments du document XML. Cette classe tend gnralement la classe DefaultHandler, qui fournit des implmentation vide des mthodes. On ne rednit normalement quune partie des mthodes.
void characters (char[] ch, int start, int length) appele pour traiter du texte. Attention, le texte traiter commence dans le tableau ch la position start, et a pour longueur length. void endDocument () appel la n du document.
1. plus prcisment org.xml.sax.helpers.DefaultHandler

108

CHAPITRE 5. JAVA ET XML

void endElement (String namespaceURI, String localName, String qName) appel la n dun lment. Le nom de llment est stock dans localName ou qName, voire les deux, selon la conguration du systme. La distinction entre ces deux noms est lie lutilisation possible d espaces de nomages , qui sont lquivalent XML des packages java. void processingInstruction (String target, String data) appel pour traiter les instructions entre <? ... ?> void startDocument () appele au dbut du document. void startElement (String namespaceURI, String localName, String qName, Attributes atts) appele au dbut dun lment. Le nom de llment est trait soit dans localName, soit dans qName. Les attributs sont stocks dans le tableau associatif atts traitement des attributs : les attributs sont grs au travers dune interface spcique, Attributes. Les mthodes les plus importantes de cette interface sont : int getLength () renvoie le nombre dattributs. String getQName (int index) renvoie le nom du indexe attribut. String getValue (int idx) renvoie la valeur du ie attribut. String getValue (String qName) renvoie la valeur dun attribut dont on connat le nom. Utilisation de lespace de nomage Le comportement de lanalyseur est gouvern par deux proprits : http://xml.org/sax/features/namespaces et http://xml.org/sax/features/namespace-prefixes. Leur valueur peut tre consulte et xe laide des mthodes : boolean getFeature (String name) throws SAXNotRecognizedException, SAXNotSupportedException

5.2. LES API JAVA


void setFeature (String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException

109

Si http://xml.org/sax/features/namespace-prefixes est vrai, la valeur qName sera xe. Elle contient le nom complet de la balise, prxe par le nom de lespace de nomage. Inversement, http://xml.org/sax/features/namespace-prefixes indique que namespaceURI et localName seront renseigns.
Appel de lanalyseur sur le document

On analyse le document en appelant la mthode parse de la classe SAXParser. Exemple :


// Cration du builder (tend DefaultHandler) TestXML handler= new TestXML(); // Cration du constructeur danalyseurs : SAXParserFactory factory= SAXParserFactory.newInstance(); // On veut dans cet exemple un analyseur non validant factory.setValidating(false); // construction de lanalyseur. SAXParser parser= factory.newSAXParser(); // On construit une InputSource partir du nom du fichier traiter InputSource src= new InputSource("toto.xml"); // On lance lanalyse // premier argument : document analyser // second argument : builder utiliser. parser.parse(src, handler);

Utilisation de SAX (ou DOM) sans DTD

Il arrive parfois quun document XML fasse rfrence une DTD dont on ne dispose pas. Dans ce cas, les bibliothques java signaleront un problme mme si on ne demande pas de validation. En effet, la DTD nest pas utilise uniquement pour valider le document, mais aussi pour xer les valeurs de certains attributs (valeurs par dfauts), remplacer les entits par leurs valeurs... Quand on ne dispose pas de la bonne DTD, la mthode suivre est den fournir une qui soit vide. On peut rednir pour cela la mthode resolveEntity, qui sera appele lors de lanalyse pour rcuprer le code qui dcrit une entit donne (ici la dtd). Supposons que nous voulions lire un document utilisant la dtd file:///office.dtd, sans disposer de celle-ci. On pourra crire la mthode resolveEntity suivante :
public InputSource resolveEntity(String publicId, String systemId) throws SAXException { if (systemId.equals("file:///office.dtd")) { // On construit la vole une dtd vide return new InputSource(

110

CHAPITRE 5. JAVA ET XML


new StringReader( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")); // Renvoyer null => le systme normal // rsolution de noms sera utilis. return null; de

} else

5.3

XSL et java

On peut utiliser des feuilles de style XSLT partir de java. Un point trs intressant est que la source et la destination de ces transformations peuvent tre, non seulement de simples chiers, mais aussi des documents DOM ou des analyseurs SAX.

TestXSL.java import javax.xml.transform.*; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; public class TestXSL { public static void main(String[] args) { try { // Objet qui reprsente la feuille de style xslt Source xslSource= new StreamSource("doc.xsl"); // Document dorigine Source xmlSource= new StreamSource("exemple.xml"); // Document html cr par le filtre Result result= new StreamResult("result.html"); // Construction du filtre XSLT : // - on rcupre un crateur de filtre TransformerFactory tfactory= TransformerFactory.newInstance(); // - on lutilise pour crer le filtre proprement dit Transformer t= tfactory.newTransformer(xslSource); // Application du filtre. Cest fini. t.transform(xmlSource, result); } catch (TransformerException e) { e.printStackTrace(); } } }

5.4. QUELQUES OUTILS JAVA UTILISANT XML

111

5.4 5.5

Quelques outils java utilisant XML Appendice : un fragment de la description du langage XML

5.4.1 SVG et Batik

Les documents ofciels qui dcrivent le langage XML ne sont pas forcment trs facile lire. Ils utilisent la notation Extended Backus-Naur Form (EBNF). Cette dernire emploie les oprateurs | , * , + et ? avec le mme sens que les DTD. La grande diffrence est que toute chane de caractre constante est mise entre guillemets simples. Nous allons analyser en dtail la description de la dclaration dun lment dans une DTD.
elementdecl contentspec ::= <!ELEMENT Name contentspec > ::= EMPTY | ANY | Mixed | children

children ::= (choice | seq) (? | * | +)? cp ::= (Name | choice | seq) (? | * | +)? choice ::= ( cp ( | cp )* ) seq ::= ( cp ( , cp )* ) Mixed ::= ( #PCDATA ( | Name)* )* | ( #PCDATA )

112

CHAPITRE 5. JAVA ET XML

113

Chapitre 6 Swing Avanc


6.1 Patterns en swing : lexemple de JTable

6.1.1 Le pattern Observateur


Toutes les classes graphiques de swing sont contruites sur le schma vue/modle. Dans la plupart des cas, un modle par dfaut est automatiquement construit :
// Cre une table de 1000 lignes et 10 colonnes : JTable table= new JTable(1000,10); getContentPane().add(new JScrollPane(table));

La classe JTable permet daccder ce modle, grce la mthode getModel :


TableModel model = table.getModel(); model.setValueAt("Une chane", 3, 4); model.setValueAt(new ImageIcon("icon.jpg"),2,2); model.setValueAt(new Boolean(false), 1,1);

Le code suivant, par exemple, aura pour effet de dupliquer en temps rel les donnes de la table :
table= new JTable(1000,10); getContentPane().add(new JScrollPane(table)); getContentPane().add(new JScrollPane(new JTable(table.getModel())));

Linterface JTableModel dnit un certain nombre de mthodes, dont la classe AbstractTableModel fournit une implmentation par dfaut. En pratique, quand on a besoin dun modle spcique, on tend AbstractTableModel si cest possible, plutt que dimplmenter entirement JTableModel.
Class getColumnClass (int columnIndex) Retourne la classe correspondant aux entres de la colonne. AbstractTableModel, la valeur retourne est toujours Object.class.

Dans

114 int getColumnCount () retourne le nombre de colonnes. String getColumnName (int columnIndex) retourne le nom de la colonne i. int getRowCount () retourne le nombre de lignes.

CHAPITRE 6. SWING AVANC

Object getValueAt (int rowIndex, int columnIndex) retourne la valeur de la cellule rowIndex, columnIndex. boolean isCellEditable (int rowIndex, int columnIndex) retourne vrai si la case rowIndex, columnIndex est ditable. void setValueAt (Object aValue, int rowIndex, int columnIndex) xe la valeur de la case rowIndex, columnIndex. void addTableModelListener (TableModelListener l) ajoute un observateur, qui sera prvenu quand le modle sera modi. void removeTableModelListener (TableModelListener l) supprime un observateur.

La classe AbstractTableModel propose de plus des mthodes pour prvenir les observateurs :
void fireTableCellUpdated (int ligne, int colonne) avertit les observateurs que la cellule ligne, colonne a t modie. void fireTableDataChanged () avertit les observateurs que les donnes de la table ont chang. void fireTableRowsDeleted (int firstRow, int lastRow) avertit les observateurs que les ranges dindices compris entre i0 et i1, inclus, ont t supprimes. void fireTableRowsInserted (int firstRow, int lastRow) avertit les observateurs que les ranges dindices compris entre i0 et i1, inclus, ont t insres void fireTableRowsUpdated (int i0, int i1) avertit les observateurs que les ranges dindices compris entre i0 et i1, inclus, ont t modies. void fireTableStructureChanged () avertit les observateurs que la structure de la table a chang. void fireTableChanged (TableModelEvent e) Expdie lvnement e qui reprsente les modications faites la table tous ses observateurs. Gnralement, on utilisera plutt les mthodes prcdentes.

6.2. LE PATTERN COMMANDE EN SWING : ACTIONS ET EDITS

115

6.2

Le pattern commande en swing : actions et edits

Le design pattern commande est utilis plusieurs reprises dans swing, des ns diffrentes.

6.2.1 Actions et le pattern commande


Il arrive souvent dans une interface graphique quune opration soit ralisable de plusieurs faon : par un menu, un bouton, un raccourci clavier...

6.2.2 Undo, classes textes et design pattern commande