Programmation par les Objets en Java
Type Abstrait de donnée : une pile
(TD2)
Najib Tounsi
(Lien permanent: http://www.mescours.ma/Java/TD/tdJava2.html
(.pdf
))
L'objectif de ce TD est de programmer en utilisant un type abstrait de données (pile de caractères ici) réalisée par une classe Java.
Sommaire
On va programmer la classe Pile de caractères, représentée par un tableau et un indice de sommet de pile.
Compléter la classe suivante (à créer dans un fichier Pile.java):
public class Pile {
//
// Déclarations des attributs de la pile
//
static final int MAX = 8;
char t[];
int top;
//
// Programmation des opérations (méthodes) de la pile
//
public Pile() {
// Initialise une pile vide
t = new char[MAX];
top = -1;
}
public void empiler(char c) {
// Empile le caractère donné en paramètre
if (!estPleine())
t[++top] = c;
else
System.out.println("Pile pleine");
}
public char sommet() {
// Retourne le caractère au sommet de la pile, sinon '\0'
// ... a compléter ...
}
public void depiler() {
// décapite la pile (retire le sommet )
// ... a compléter ... }
public boolean estVide() {
// Teste si la pile est vide
return (top < 0);
}
public boolean estPleine() {
// teste si la pile est pleine
// ... à completer ...
}
}; // class Pile
Exercice 1) Ecrire un programme qui lit une chaîne de caractère et l'imprime inversée.
Algorithme :
Indications :
TestPile.java
char monChar; Scanner clavier = new Scanner(System.in);
monChar = clavier.next().charAt(0);
#
'.Retrouver la
solution ici ( http://www.mescours.ma/Java/TD/TestPile.java
).
Exercice-2 ) Ecrire un programme qui lit une un texte contenant une série de parenthèses et qui
(
il l'empile sur une pile p)
il dépile la pile p#
.
A la fin du texte lu, si la pile est vide l'expression est bien parenthésée. Sinon, il y a plus de parenthèses ouvrantes que de parenthèses fermantes. Si la pile est vide prématurément, lors d'un dépilement, alors il y a plus de parenthèses fermantes que de parenthèses ouvrantes.
On va créer une page Web de documentation de la classe Pile. Il doit y avoir
Dans le fichier Pile.java
contenant la classe Pile,
ajouter en début de fichier un commentaire qui commence par /**
.
C'est le commentaire générale de la classe. Exemple :
/**
Classe Java correspondant à une pile
Un pile est un objet sur lequel on empile ...
etc...
*/
Ensuite, avant chaque déclaration de méthode, ajouter le commentaire qui documente la méthode. Exemple :
/**
* Empile le caractère donné
*/
public void empiler(char c){...}
...
On peut alors créer les pages documentation de la classe Pile avec la
commande javadoc
$ javadoc Pile.java
Un certain nombre de fichiers sont alors créés. L'un des fichiers est index.html
qui est la page Web principale.
On peut améliorer la documentation finale en rajoutant des lignes
commentaires @param
, @return
, @see
,
pour documenter les paramètres. Exemple : Source
à documenter, documentation
générée.
Une exception est un cas particulier (ou erreur) qui se produit dans un programme. Par exemple pile vide en cas de dépilement, rencontre d'un caractère nom numérique lors de la lecture d'un nombre etc.
L'exemple simple suivant est une méthode qui calcule la factorielle d'un entier, et qui lève une exception quand l'entier est négatif.
static public int fact(int x) throws ExceptionFactNegatif {
if ( x < 0 ) throw new ExceptionFactNegatif();
else {
// calcul factorielle dans int f ...
return f;
}
}
On rajoute au profile de la méthode le mot clé throws
et le type d'objet levé, qui est ici le classe ExceptionFactNegatif
.
(voir plus bas).
L'utilisation de cette méthode doit s'attendre, grâce à une instruction try
, à une éventuelle levée
d'exception et la capter, grâce à une instruction catch
,
pour pouvoir la traiter.
int n = ...
try {
int f = fact(n);
}
catch (ExceptionFactNegatif e) {
System.out.println("Valeur negative pour factorielle");
e.printStackTrace();
}
try
indique un bloc
d'instructions dans lequel une exception peut être levée "une erreur
peut se produire".
Le bloc catch
contient les
instructions à exécuter dans le cas où un type d'exception s'est produit
dans le try
correspondant. Ici, on imprime une message
pour la circonstance. catch
est
paramétré par l'exception à capter. ici objet e
de classe ExceptionFactNegatif
.
On peut utiliser cet objet e
justement, pour suivre la trace de l'exception produite, avec e.printStackTrace()
en plus du message à imprimer.
Le résultat de la séquence de programme précédente exécutée pour n = -1 est:
Valeur negative pour factorielle
ExceptionFactNegatif
at TestException.fact(TestException.java:17)
at TestException.main(TestException.java:5)
La classe correspondant à l'exception souhaitée, ExceptionFactNegatif
ici, est donnée par:
class ExceptionFactNegatif extends Throwable {};
Classe qui ne contient rien. Seul son nom suffit. (N'est elle pas une exception?...)
Le fait c'est qu'elle est sous classe de la classe prédéfinie Throwable
.
Condition nécessaire pour pouvoir être soulevée comme exception.
A un même bloc try
peuvent correspondre deux blocs catch
.
On peut ajouter à l'exemple ci-dessus le cas de factorielle qui dépasse la
capacité d'un int
. Factorielle 13 est déjà 6 227 020 800.
On crée donc une deuxième exception,
class ExceptionFactSuperieur12 extends Throwable {};
et on écrira :
try {
int f = fact(n);
}
catch (ExceptionFactNegatif e) {
System.out.println("Valeur negative pour factorielle");
e.printStackTrace();
}
catch (ExceptionFactSuperieur12 e) {
System.out.println("Valeur > 12 pour factorielle");
e.printStackTrace();
}
Exercice-3)
Suivant ce même modèle, reprendre la classe pile et traiter les cas d'une pile vide (dans dépiler et sommet) et d'une pile pleine (dans empiler).
Indication :
On définira deux classes ExceptionPileUnderflow
et ExceptionPileOverflow
correspondant respectivement aux cas débordement de pile par en bas, pile
vide, ou débordement par en haut, pile pleine.
On reprogrammera les opération de la classe pile en conséquence, par exemple:
public char sommet() throws ExceptionPileUnderflow {
// Retourne le caractère au sommet de la pile
if (!estVide())
return t[top];
else
throw new ExceptionPileUnderflow();
}
etc...
On reprendra ensuite le programme TestPile.java
avec
cette fois-ci des blocs try
/catch
.
Une solution : PileException.java, TestPileException.java. (voir la
version .html
pour les liens)
Exercice-4)
a) Réfléchir à un algorithme qui
vérifie si une chaîne (ou expression) est bien parenthésée: une parenthèse
fermante est en correspondance avec une parenthèse ouverte. "Parenthèse" à
prendre au sens large parmi les symboles: ( < [ { } ] > )
.
Exemple :
{[(a+51)-(c)]}
est correcte
{(a+b)]
est incorrecte ( ]
ne correspond pas à {
),
ainsi que (a+b))
(parenthèse fermante en trop) ou
((a+b)
(parenthèse ouvrante en trop)
Indications :
{
,
on l'empile[
,
on l'empile(
,
on l'empilea+51
,
on lit )
,
elle correspond au sommet de la pile (4), on dépile celle-ci -
,
on lit (
,
on l'empilec
,
on lit )
,
elle correspond au sommet de la pile (6), on dépile celle-ci ]
,
il correspond au sommet de la pile (7), on dépile celle-ci}
,
elle correspond au sommet de la pile (8), on dépile celle-ci. On a
fini la lecture. Si on finit une pile vide, l'expression est
correctement parenthésée.b) Utiliser la pile de l'exercice précédent pour programmer cet algorithme.
That's all folks.
Evaluation :
Certains exercices seront évalués à la demande et corrigés par l'encadrant du TP.