Travaux Pratiques n°1 (Java)
Table des matières
Objectifs (2h)
- Savoir compiler un code Java
- Savoir documenter un code Java
- Savoir exécuter un code Java
- Savoir lire les messages d'erreur Java
- Savoir parcourir et utiliser l'API du SDK
Présentation générale de Java et du Standard Development Kit (SDK)
Le SDK regroupe un ensemble d'outils permettant principalement de compiler et d'exécuter des programmes Java. Actuellement, la dernière version stable est Java SE 1.7.0 et est téléchargeable sur le site Java SE d'Oracle.
Java est un langage interprété, ce qui signifie qu'un programme compilé n'est pas directement exécutable par le système d'exploitation mais il doit être interprété par un autre programme, qu'on appelle interpréteur.
Le compilateur javac
javac est le compilateur fourni dans le SDK permettant de
compiler un fichier source .java. Ce code source est alors
compilé par le compilateur javac en un langage appelé
bytecode et enregistre le résultat dans un fichier dont
l'extension est .class
. Pour compiler une classe Livre
contenue
dans un fichier Livre.java
on exécutera donc l'instruction
suivante :
javac Livre.java
L'interpréteur java et la machine virtuelle
Le bytecode n'est pas directement exécutable. Il doit
être interprété par une machine virtuelle Java qui le
traduit en un langage adapté au système d'exploitation. Le
programme java fourni dans le SDK lance une machine virtuelle
pour interpreter une classe compilée. Attention :
l'extension .class ne doit pas être précisée dans l'instruction
d'interprétation. Pour exécuter la classe Livre
compilée dans
un fichier Livre.class
, on écrit donc :
java Livre
Séparation des sources et des classes compilées
En général, les fichiers contenant le code source des
classes sont séparés des fichiers contenant le bytecode pour
mieux structurer les différentes parties du programme. Pour que
les fichier créés par une compilation le soient dans un autre
répertoire on utilise l'option -d
. Par exemple :
javac -d /MonRepertoire/Java/classes Livre.java
Lorsque le bytecode ne se situe pas dans le répertoire courant, il faut signaler à la commande java
où il se trouve grâce à l'option classpath
. Par exemple :
java -classpath /MonRepertoire/Java/classes Livre
Exercice 1
Créez un répertoire tp1
(avec la commande md sous Windows, mkdir sous Linux ou avec l'exploreur de votre choix). Nous allons mettre les sources dans un répertoire nommé src
et les .class
dans un répertoire nommé bin
(à créer comme précédemment).
Ouvrez un éditeur de texte, puis créez un fichier vide nommé
HelloWorld.java
dans le répertoire
tp1/src
.
Exercice 2
Ecrivez le code source d'une classe
HelloWorld
dans le fichier HelloWorld.java
. La classe HelloWorld
contient un attribut privé message
qui est du type String
.
HelloWorld
doit également contenir deux méthodes :
un constructeur qui attribue une valeur au message et une
méthode public String getMessage()
qui renvoie la
valeur du message. Compilez cette classe en séparant bien le
code source et le bytecode grâce à la commande suivante, depuis le répertoire tp1
:
javac -d bin src/HelloWorld.java
Ceci signifie que la classe à compilée est dans le fichier HelloWorld.java
qui est dans le répertoire src
et que le fichier .class
doit être généré dans le répertoire bin
, comme dans la figure suivante :
Classe exécutable et méthode main()
La classe HelloWorld
n'est pas exécutable dans
son état actuel. Une classe exécutable est une classe qui
contient une méthode spécifique (main
) utilisée
comme point de départ de l'exécution. La méthode
main
d'une classe s'écrit de la manière suivante :
public static void main(String[] args){ //début du code à exécuter }
Exercice 3
Ajoutez une méthode main
à
la classe HelloWorld
. Dans cette méthode créez une
instance de HelloWorld
et affichez son message.
Pour afficher du texte à l'écran utilisez la méthode
System.out.println(String t)
. Compilez comme précédemment.
Savoir lire les messages d'erreur Java
Java est très bavard lorsqu'il vous signale une erreur d'exécution. Il affiche notamment ce qu'on appelle une trace de la pile d'appels qui ont amené à cette erreur. Cette liste d'appels est affichée de l'appel le plus interne à l'appel le plus externe. Pour trouver l'origine de l'erreur (si elle est dûe à votre code), parcourez cette liste jusqu'à trouver une classe de votre propre code. Le message d'erreur Java affiche également la ligne du code de l'appel. Pratique pour directement aller à la source de l'erreur. De plus, Java faisant usage de la notion d'exception, en lisant le type d'exception qui a généré l'erreur il est également possible d'en déduire l'origine. Par exemple, si NullPointerException
est affichée, il y a de forte chance que vous ayez oublié d'initialiser un objet (par appel à new
) avant de faire appel à un de ses attributs ou méthodes.
Exercice 4
Exécutez la classe
HelloWorld
grâce à la commande suivante :
java -classpath bin HelloWorld
car le fichier .class
à exécuter ne se situe pas dans le répertoire courant.
Les arguments de la méthode main
Vous avez vu que la méthode main
possédait la
signature suivante :
public static void main(String args[]) { ... }
Le tableau args
contient tous les arguments passés
en paramètres du programme Java. Par exemple, suite à la ligne de
commande
java MonProgramme texte1 127 unfichier.txt
le tableau args
contiendra les élément suivants :
args[0]
: la chaîne de caractères "texte1"args[1]
: la chaîne de caractères "127"args[2]
: la chaîne de caractères "unfichier.txt"
Packages
Notion de package et de classpath
Un package est un regroupement de plusieurs classes selon un
thème précis. Au niveau du code source, un package n'a pas
d'existence explicite, il n'est réellement créé que dès que sa
première classe est compilée. Pour indiquer qu'une classe
appartient à un package on utilise au tout début du fichier
contenant le code source le mot-clé
package
. Pour assigner la classe Livre
au
package biliotheque
, on écrira :
package bibliotheque; public class Livre { //contenu de la classe }
Un package peut être imbriqué dans un package plus général
et ainsi de suite (comme des dossiers). Pour désigner un
package document
imbriqué dans le package bibliotheque
on
écrira par exemple:
package bibliotheque.document;
A la compilation, des répertoires sont créés pour
correspondre aux packages des classes compilées. Les fichiers
contenant le bytecode sont enregistrés dans le répertoire de
leur package. Une classe est alors désignée par son nom de
package, suivie d'un point puis du nom de la classe. Par
exemple, pour exécuter la classe Livre
on utilise
l'instruction:
java bibliotheque.Livre
Pour que la référence à la classe Livre
soit effective, il
faut que le répertoire contenant son package soit accessible
par la machine virtuelle. Il y a deux solutions pour cela:
- Exécuter la classe à partir du répertoire contenant le
répertoire
bibliotheque
. Dans ce cas là, le packagebibliotheque
et les classes qu'il contient sont directement trouvés car ils sont dans le répertoire d'exécution. - Exécuter la classe à partir d'un autre répertoire. Il
faut alors préciser le chemin d'accès du répertoire contenant
le package
bibliotheque
. Cela se fait en utilisant l'option-classpath
comme précédemment :
java -classpath /MonRepertoire/Java/classes bibliotheque.Livre
Importation de package
Quand une classe fait référence à une autre classe, elle
doit l'importer sauf si elles se trouvent dans le même
package. Pour cela le mot-clé import est utilisé au début du
fichier source, un peu comme include
de C, comme dans
l'exemple qui suit:
package client; import bibliotheque.Livre; public class Lecteur { Livre[] emprunte; ... }
De cette manière la classe Lecteur peut utiliser la classe
Livre
. Il est également possible d'importer toutes les classes
d'un package en utilisant le symbole *
comme suit:
import bibliotheque.*;
Exercice 5
Créez un package
fr.emse.helloworld
(donc un répertoire
fr/emse/helloworld
dans le répertoire src
) et déplacez-y votre fichier
HelloWorld.java
. Déclarez que la classe
HelloWorld
appartient au package
fr.emse.helloworld
.
Compilez avec la commande suivante :
javac -d bin src/fr/emse/helloworld/HelloWorld.java
Puis exécutez-la avec la commande suivante :
java -classpath bin fr.emse.helloworld.HelloWorld
Vous devriez obtenir l'arborescence suivante :
Documentation
L'outil javadoc
javadoc est un autre programme du SDK qui créé une documentation automatique à partir du code source de classes Java. Cette documentation automatique décrit les membres d'une classe dans un format HTML. Pour créer tous les fichiers de documentation d'un package, on utilise javadoc comme suit:
javadoc -d <répertoire de destination> <nom des packages>
Le fichier principal de documentation est index.html
créé
dans le répertoire de destination.
Remarque : par défaut la commande javadoc
ne généère la documentation que pour les classes et membres public
, donc pensez à établir la visibilité de votre classe à public
. Vous pouvez également spécifier à javadoc
que vous voulez également générer la documentation pour les membres privés avec l'option -private
:
javadoc -d <répertoire de destination> -private <nom des packages>
Exercice 6
Générez la documentation de votre package
dans un répertoire tp1/doc
. Vous devriez obtenir l'arborescence suivante :
Quelques tags javadoc
javadoc peut interpréter des commentaires spécifiques
introduits dans le code source pour enrichir la documentation
générée. Ces commentaires se situent juste avant la déclaration
d'une classe, d'un attribut ou d'une méthode. Ils commencent
par /**
et se terminent par */
. Ces commentaires contiennent
une partie textuelle libre et des tags interprétés pour
certains commentaires spécifiques.
Quelques tags fréquemment utilisés
- @author : l'auteur d'une classe
- @version : le numero de version d'une classe
- @see : une référence à une classe ou un membre d'une classe intéressant pour la classe ou la méthode commentée
- @param x : Une description du paramètre d'entrée x d'une méthode
- @return : Une description de la valeur renvoyée par une méthode
Exemple de classe commentée pour javadoc
package bibliotheque; /** * Cette classe est utilisée pour représenter un livre. * * @author Laurent Vercouter */ public class Livre extends Produit { /** * Le titre du livre */ private String titre; /** * L'auteur du livre */ private String auteur; /** * Le constructeur de la classe Livre * * @param tit Le titre du livre * @param aut L'auteur du livre */ public Livre(String tit, String aut) { titre = tit; auteur = aut; } /** * Cette méthode renvoie une chaîne de caractères qui décrit * textuellement le livre (par son titre, son auteur et l'éditeur) * * @return Une chaîne de caractère décrivant le livre */ public String description() { return "\""+titre+"\" de "+auteur+" edite par "+editeur; } }
Exercice 7
Ajoutez des commentaires et des tags pour que vos classes soient correctement documentées. Par la suite, toutes vos classes devront être commentées de cette manière.
l'API du SDK
Une bonne documentation est indispensable pour faciliter l'usage des classes développées (même quand on les a soi-même écrites !). Un très grand nombre de classes générales ont déjà été écrites par d'autres développeurs et il est souvent très utile de les ré-utiliser plutôt que de tout ré-implémenter. Sun fournit ainsi de nombreuses classes générales dans une API (Application Programmer Interface). Ce sont des outils allant de la simple sortie standard sur la console jusqu'au chargement d'image, gestion du réseau, GUI, … La plupart de ces classes sont indépendantes du type d'application développées et sont utilisables dans de nombreux projets.
La documentation de l'API du SDK est alors un outil essentiel pour tout programmeur Java car elle permet de comprendre ce que fait une classe et comment bien l'utiliser. Elle est consultable en ligne sur le site Java SE d'Oracle.
Tous les packages de l'API du SDK 1.7.0 y sont décrits. Pour trouver s'il existe une classe pour un problème spécifique, on parcourt en général le package correspondant à cette spécificité. Les packages les plus simples et les plus fréquemment utilisés sont :
- java.lang : classes de base du langage
- java.util : classes "utilitaires" (pour des problèmes fréquents comme la manipulation d'ensembles, …)
- java.io : classes pour la gestion d'entrées/sorties
- java.net : classes pour la programmation réseau
- java.awt et javax.swing: classes pour la programmation d'interfaces graphiques
Consultons par exemple la documentation associée à la classe
java.lang.String
:
- Cliquez dans la zone en haut à gauche sur le package
java.lang
. Ce clic a pour effet d'afficher seulement le contenu du package dans la zone en bas à gauche. - Cliquez sur la classe
String
pour afficher la documentation associée, dans la partie centrale du navigateur. - Consultez la documentation de la classe pour constater que la première partie est un descriptif général de la classe, puis suit la liste des champs, constructeurs et méthodes. Un descriptif complet de chaque membre de la classe est accessible par un clic sur son nom.
Exercice 8
Identifiez, dans la classe
java.lang.String
, une méthode pour remplacer dans une chaîne de
caractères chaque apparition de l'expression "abc
" par
l'expression "de
".
Exercice 9
L'objectif de cet exercice n'est pas de produire du code Java mais d'apprendre à naviguer dans la documentation de l'API.
- Trouvez une classe puis une de ses méthodes pour tester si un fichier existe à partir de son chemin d'accès (répertoire + nom du fichier).
- Trouvez une classe permettant d'obtenir aléatoirement un nombre entier. Trouvez aussi la méthode requise pour cette opération.
- Trouvez une classe pour décrire une exception qui apparaît lors d'une erreur de conversion d'une chaîne de caractères en une valeur numérique.
Collections
Une collection est un objet qui référence plusieurs objets.
La plupart des classes représentant des collections sont
contenues dans le package java.util
. Les classes
de type collection implémentent des méthodes similaires pour
accéder au groupe d'objets référencés. Les principales méthodes
sont :
add
pour ajouter un objet à la collectioncontains
pour tester si un objet appartient à la collectionremove
pour retirer un objet d'une collectionsize
pour connaître la taille d'une collection
S'il existe différentes classes de collection, c'est parce que chacune présente des propriétés spécifiques :
- Les ensembles qui regroupent des objets distincts
de manière non ordonnée. Par exemple, la classe
java.util.HashSet
. - Les listes qui regroupent des objets selon un
ordre donné. Par exemple, la classe
java.util.Vector
. - Les maps qui associent à chaque objet du groupe
une clé pour accéder directement à un objet. Par
exemple, la classe
java.util.Hashtable
.
Depuis la version 1.5 du SDK, les collections sont typées, c'est-à-dire qu'on doit désormais préciser la classe des objets présents dans une collection. Par exemple, pour déclarer puis instancier une liste de chaînes de caractères, on écrira :
Vector<String> maListe; maListe = new Vector<String>();
Le parcours d'une collection peut s'écrire de manière
simplifiée dans une boucle for
. Il suffit de référencer le type
d'objets de la collection avec un nom de variable comme suit :
for (String s: maListe) { System.out.println(s); }
Ce qui signifie ici : pour chaque String
(que
l'on nomme s
) contenu dans maListe
,
on écrit l'objet sur la sortie standard. Cette boucle comptera
autant d'itérations qu'il y a d'éléments dans
maListe
et à chaque itération, s
aura
pour valeur un élément de maListe
.
Exercice 9
Modifier la classe
HelloWorld
pour qu'elle encapsule (i.e. contienne un attribut) et affiche un
ensemble de messages. Utilisez la classe
java.util.Vector
pour faire référence à plusieurs
chaînes de caractères.
Exercice 10
Ajouter à la classe
HelloWorld
une méthode String getMessage(int
i)
permettant de récupérer le ième message de la
liste et une méthode void addMessage(String message)
pour ajouter un message en fin de liste.
Exercice 11
Modifiez votre main
pour récupérer les messages à partir des arguments du main
et pour afficher tous les messages contenus dans l'instance de la classe HelloWorld
.
Rendu du travail
Le TP doit être rendu en fin séance, quel que soit son état d'avancement. Envoyez le source des classes (.java) ainsi que les classes compilées (.class) dans une archive zip (veiller à bien ajouter les sources !) à Gauthier Picard à la fin, avec comme sujet [LCPOO] TP1a <nom1> <nom2>. L'absence d'envoi sera sanctionnée dans la note finale.