Problème de Fiabilité
Tout programme comporte des erreurs (bugs) ou est susceptible de générer des erreurs (e.g suite à une action de l’utilisateur, de l’environnement, etc …).
La fiabilité d’un logiciel peut se décomposer en deux grandes propriétés :
- la robustesse qui est la capacité du logiciel à continuer de fonctionner en présence d’événements exceptionnels tels que la saisie d’informations erronées par l’utilisateur
- la correction qui est la capacité d’un logiciel à donner des résultats corrects lorsqu’il fonctionne normalement.
Exceptions
Comment traiter les Erreurs
Une première méthode consiste
- à prévoir les érreurs possibles.
- associer chaque erreur possible avec un code d’erreur
- Lorsqu’une erreur est detectée, la fonction retourne le code correspondant
Chaque appel de fonction doit être vérifié. Un oubli peut entrainer d’autres erreurs pouvant avoir des conséquences tout en passant inaperçu.
Comment traiter les Erreurs
f = openFile(filename); // Comment signaler une erreur ?
if(f == null) {
if(getLastError() == 12) {
// fichier inexistant par exemple
}
}
else {
// pas d'erreur
}
autre exemple, la librarie FMOD en C. Toutes les fonctions retournent un code pour le resultat.
FMOD_RESULT result = FMOD_System_PlaySound(system, FMOD_CHANNEL_FREE, unSon, 0, NULL);
if(result = FMOD_OK) {
// ok
} else if(result == FMOD_ERR_FILE_NOTFOUND) {
...
} else if(result == FMOD_ERR_INVALID_SPEAKER) {
...
}
Exceptions Java
Java propose un mécanisme : les exceptions
- Les différent types d’erreurs sont modélisés par des classes.
- La gestion des erreurs est séparée des instructions normales du programme. Il y a un bloc d’essai et un bloc de traitement d’erreur.
Exceptions Java
Définition : Le terme exception désigne tout événement arrivant durant l’exécution d’un programme interrompant son fonctionnement normal.
En java, les exceptions sont matérialisées par des instances de classes héritant de la classe java.lang.Throwable.
A chaque évènement correspond une sous-classe précise, ce qui peut permettre d’y associer un traitement approprié.

Le bloc try
Définition : La clause try s’applique à un bloc d’instructions correspondant au fonctionnement normal mais pouvant générer des erreurs. (exemple : l’ouverture d’un fichier).
try {
...
...
}
Attention : un bloc try
ne compile pas si aucune de ses instructions n’est susceptible de lancer une exception.
Le bloc catch
Définition : La clause catch s’applique à un bloc d’instructions définissant le traitement d’un type d’erreur. Ce traitement sera lancé sur une instance de la classe d’exception passée en paramètre.
try{
...
}
catch(TypeErreur1 e) {
...
}
catch(TypeErreur2 e) {
...
}
Blocs try-catch
Tout bloc try
doit être suivit par au moins un bloc catch
ou par un bloc finally
(étudié plus loin).
Tout bloc catch
doit être précédé par un autre bloc catch
ou par un bloc try
.
Un ensemble composé d’un bloc try
et d’au moins un bloc catch
est communément appelé bloc try-catch
.
Lever une exception
Définition : Lorsqu’une instruction du bloc d’essai génère une erreur et y associe une exception, on dit qu’elle lève (lance) cette exception.
Définition : Lorsqu’un bloc de traitement d’erreur est déclenché par une exception, on dit qu’il traite (capture) cette exception.
Fonctionnement
Fonctionnement
Fonctionnement
Fonctionnement
Fonctionnement
Le fonctionnement d’un bloc try-catch est le suivant :
- si aucune des instructions du bloc d’essai ne lance d’exception, il est entièrement exécuté et les blocs de traitement d’erreur sont ignorés.
- si une des instructions du bloc d’essai lance une exception, alors toutes les instructions du bloc d’essai après elle sont ignorées et le premier bloc de traitement d’erreur correspondant au type de d’exception lancée est exécuté. Tous les autres blocs de traitement d’erreur sont ignorés.
Les Types d’Exceptions
Lever une exception
Définition : Les exceptions de type Error
sont réservées aux erreurs qui surviennent dans le fonctionnement de la JVM. Elles peuvent survenir dans toutes les portions du codes.
- OutOfMemoryError : survient lorsque la machine virtuelle n’a plus de place pour faire une allocation et que le GC ne peut en libérer.
- NoSuchMethodError : survient lorsque la machine virtuelle ne peut trouver l’implémentation de la méthode appelée.
- StackOverflowError : survient lorsque la pile déborde après une série d’appel récursif trop profond.
- etc…
Les Types d’Exceptions
Lever une exception
Définition : Les exceptions de type RuntimeException correspondent à des erreurs qui peuvent survenir dans toutes les portions du codes.
- ArithmeticException : division par zéro (entiers), etc …
- IndexOutOfBoundsException : dépassement d’indice dans un tableau.
- NullPointerException : référence null alors qu’on attendait une référence vers une instance.
- etc…
int a = 0;
try {
int x = 1 /a;
System.out.println(" x = " + x); }
catch (ArithmeticException e)
{
System.out.println("division par 0 : 1 / " + a);
}
Les Types d’Exceptions
Lever une exception
Définition : On appelle exception contrôlée, toute exception qui hérite de la classe Exception et qui n’est pas une RuntimeException. Elle est dite contrôlée car le compilateur vérifie que toutes les méthodes l’utilisent correctement.
- EOFException : fin de fichier …
- FileNotFoundException : fichier inexistant.
- ClassNotFoundException : erreur dans le chargement d’une classe.
- etc…
Exceptions Controlées
Toute exception contrôlée, du JDK ou personnalisée, pouvant être émise dans une méthode doit être :
- soit capturée dans cette méthode. Elle est alors lancée dans un bloc try auquel est associé un catch lui correspondant.
- soit être indiquées dans le prototype de la méthode à l’aide du mot clé
throws
.
Exemple
On veut faire une fonction qui supprime le fichier “/temp.txt”
On peut utiliser la méthode Files.delete(Path p)
documentation.
public static void f() {
Path file = new File("test.txt").toPath();
try {
Files.delete(file);
} catch (NoSuchFileException x) {
System.err.format("no such file: %s%n", file);
} catch (IOException x) {
System.err.format("delete error: %s%n", x);
}
// Les Exceptions SecurityException héritent de
// RuntimeException donc ce n'est pas obligatoire de les attraper
}
public static void main(String[] args) {
f();
}
Solution 2
public static void f() throws IOException
{
Path file = new File("test.txt").toPath();
Files.delete(file);
}
public static void main(String[] args) {
try {
f(); // peut jeter une exception
} catch (NoSuchFileException x) {
// C'est parfois quand même utile de spécialiser
// la gestion des exceptions
System.err.format("no such file: %s%n", file);
}
catch(IOException e) {
System.out.println(e);
}
}
Exceptions Personnalisées
Exceptions Personnalisées
On peut définir ses propres exceptions en définissant une sous-classe de la classe Exception
.
public class MonException extends Exception {
private int x;
public MonException(int x) {
this.x = x;
}
public String toString() {
return "Valeur incorrecte : " + x;
}
}
Lancer une exception
Définition : Pour lancer une exception, on peut utiliser la clause throw
.
public class Main {
public static void main (String[] args) {
try {
int size = Integer.parseInt(args[1]);
if (size < 0) {
throw new MonException(size);
}
int[] tab = new int[size] ;
System.out.println("Taille du tableau :" + tab.length);
} catch (MonException e) {
System.err.println(e);
}
}
}
Lancer une exception
public class Main {
public static void main (String[] args) {
try {
int size = Integer.parseInt(args[1]);
if (size < 0) {
throw new MonException(size);
}
int[] tab = new int[size] ;
System.out.println("Taille du tableau :" + tab.length);
} catch (MonException e) {
System.err.println(e);
}
}
}
>> java TestTableau 3
Taille du tableau : 3
>> java TestTableau -1
Valeur incorrecte : -1
Exceptions Personnalisées
public class ExceptionCordiale extends Exception {
public ExceptionCordiale(String err) {
super("Je suis au regret de vous annoncer que "+err+". Veuillez nous excuser pour la gène occasionnée.");
}
}
Exceptions Personnalisées
class TestTableau {
private static double sqrt(int i) throws ExceptionCordiale {
if(i < 0) throw new ExceptionCordiale("le nombre ne doit pas être négatif");
return Math.sqrt(i);
}
public static void main (String[] args) {
try {
int i = Integer.parseInt(args[1]); // Peut aussi lancer une exception
System.out.println(sqrt(i));
} catch(Exception e) {
System.out.println(e);
}
}
}
Le bloc finally
Définition : La clause finally
définit un bloc d’instruction qui sera exécuté même si une exception est lancée dans le bloc d’essai. Elle permet de forcer la bonne terminaison d’un traitement en présence d’erreur, par exemple : la fermeture des fichiers ouverts.
try {
...
}
catch (...) {
...
}
finally {
...
}
Le bloc finally
Le code de la clause finally sera toujours exécuté :
- si la clause try ne lance pas d’exception : exécution après le try (même s’il contient un return).
- si la clause try lance une exception traitée par un catch : exécution après le catch (même s’il contient un return).
- si la clause try lance une exception non traitée par un catch : exécution après le lancement de l’exception.
Attention : un appel à la méthode System.exit()
dans le bloc try ou dans un bloc catch arrête l’application sans passer par la clause finally
La clause finally : exemple.
class TestTableau b {
public static void main (String[] args) {
try{
int x = Integer.parseInt(args[1]);
if (x < 0) { throw new MonException(x); }
System.out.println(x);
}
catch (MonException e) {
System.err.println(e);
}
finally {
System.out.println("Tout est bien qui ...");
}
}
}
>> java TestTableau -1
Valeur incorrecte : -1
Tout est bien qui ...
Pourquoi propager les exceptions ?
Plus une méthode est éloignée de la méthode main dans la pile d’exécution, moins elle a de vision globale de l’application. Une méthode peut donc avoir du mal à savoir traiter une exception.
Il est souvent difficile pour une méthode effectuant un petit traitement de décider si une exception est critique :
“Il vaut mieux laisser remonter une exception que de décider localement d’interrompre l’ensemble du programme.”
Comment faire remonter une exceptions ?
Pour traiter une exception, on distingue finalement trois méthodes :
- Traitement local : l’exception est traitée dans la méthode.
- Traitement délégué : l’exception, qui n’est pas traitée dans la méthode, est transmise à la méthode appelante.
- Traitement local partiel : l’exception est traitée dans la méthode, puis re-lancée pour être transmise à la méthode appelante.
Traitement délégué
public void f() throws FileNotFoundException {
monFichier = new FileInputStream("./essai.txt");
}
public void g() {
try {
f();
} catch (FileNotFoundException e) {
System.err.println("Traitement délégué à g");
}
}
Traitement local partiel
public void f() throws FileNotFoundException {
try {
monFichier = new FileInputStream("./essai.txt");
} catch (FileNotFoundException e) {
System.err.println("Traitement local par f");
throw e;
}
}
public void g() {
try {
f();
} catch (FileNotFoundException e) {
System.err.println("Traitement délégué à g");
}
}
Traitement local partiel 1
public void f() throws FileNotFoundException {
try {
monFichier = new FileInputStream("./essai.txt");
} catch (FileNotFoundException e) {
System.err.println("Traitement local par f");
throw e;
}
}
public void g() {
try {
f();
} catch (FileNotFoundException e) {
System.err.println("Traitement délégué à g");
}
}
Traitement local partiel 2
public void f() throws MonException {
try {
monFichier = new FileInputStream("./essai.txt");
} catch (FileNotFoundException e) {
System.err.println("Traitement local par f");
throw new MonException();
}
}
public void g() {
try {
f();
} catch (MonException e) {
System.err.println("Traitement délégué à g");
}
}
Aucun traitement?
Si une exception remonte jusqu’à la méthode main sans être traitée par cette méthode :
- l’exécution du programme est stoppée.
- le message associé à l’exception est affiché, avec une description de la pile des méthodes traversées par l’exception
Remarque : Seul le thread qui a généré l’exception non traitée meurt ; les autres threads continuent leur exécution.
Assertions
Principe de la programmation par contrats
Pour vérifier la correction d’un programme lors de son développement, il est utile de vérifier certains invariants/conditions à des endroits bien choisis du programme.
Cette approche a été formalisée et généralisée dans la programmation par contrats.
En Java, elle peut s’appuyer sur le mécanisme des assertions qui permet au programmeur de vérifier dynamiquement des conditions
Localisation des points critiques
Lors du développement d’une application, plusieurs points critiques peuvent être à l’origine de bug. On s’attachera à contrôler :
- les pré-conditions, au début d’une méthode.
- les post-conditions, à la fin d’une méthode.
- les invariants de classe, qui doivent être préservés avant et après l’appel des méthodes de la classe.
- les invariants de boucle.
Le mot clé assert
Java 1.4 introduit un nouveau mot-clé assert qui permet d’insérer dans le code des assertions qui :
- exécutent une condition et vérifient qu’elle retourne
true
. - lancent une erreur
AssertionError
(fille de la classe Error), si la condition est false.
assert x < y ;
Une expression peut suivre l’assertion. Facultative, elle ne sert qu’a définir le message d’erreur lié à l’AssertionError.
assert x == 0 : "x n’est pas nul" ;
Les invariants logiques
Les invariants logiques sont tous les invariants induits naturellement par la logique sémantique du code. Sous forme d’assertions, ils permettent de se prémunir contre toute erreur dans les futures modifications.
coef = (x * x) / (1 + (x * x));
assert coef < 1 : "coef est compris entre 0 et 1";
assert 0 <= coef : "coef est compris entre 0 et 1";
Les invariants de contrôle de flux
Les invariants de contrôle de flux sont essentiels au bon déroulement des programmes. Ils assurent le bon enchainement des instructions. Pour en vérifier le respect, il suffit de placer des assert sur des lignes qui ne devraient pas être atteintes
switch(x) {
case -1 : ...
case 0 : ...
case 1 : ...
case default : assert false : x;
}
void foo() {
for (...) {
if (...) return;
}
assert false : "On devrait être sortie de foo";
}
Les préconditions
Lorsque l’on code une méthode privée, on peut faire la supposition que toutes ses invocations respecteront certaines conditions implicites appelées préconditions.
Cette supposition est possible car on garde le contrôle sur tous les appels à cette méthode. L’ajout d’assert offrent une méthode simple pour vérifier le respect des préconditions.
private int updateEtu(Etudiant etu, int note) {
assert 0 <= note && note <= 20 ;
...
}
Les postconditions
Les postconditions expriment des propriétés qui doivent être satisfaites en fin d’exécution d’une méthode. Elles permettent de vérifier que le traitement de la méthode s’est bien déroulé et que la valeur de retour est conforme aux spécifications.
public int sum (int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : a + " + " + b + " is too large.";
int result = a + b ;
assert result - a == b : "Sum of " + a + " + " + b + " returned " + result;
return result;
}
Les invariants de classe
Imaginons que l’on construise une classe stockant des objets qui les garde toujours triés.
public void insert(Object o) {
assert this.isSorted() : "Il y a du désordre ici";
...
}
public void add(Object o) {
int _old_size = maCollection.size();
this.maCollection.add(o);
assert this.maCollection.size() == _old_size + 1;
}
Exécution avec ou sans assertions
Les vérifications liée aux assertions, utiles en période de test, ralentissent l’exécution de l’application. Elles sont donc désactivées par défaut.
Pour activer les assertions (sauf dans les classes système) :
java -ea MonProgrammeAvecAssert
Pour activer seulement pour une classe :
java -ea:NomDuneClasse MonProgrammeAvecAssert
Pour activer seulement pour un paquetage et ses sous-paquetages (les … sont à mettre tels quels) :
java -ea:nom.dun.package... MonProgrammeAvecAssert
Pour désactiver seulement pour un paquetage (ou une classe) :
java -ea -da:nom.dun.package... MonProgrammeAvecAssert
Mauvais pratiques
Une mauvaise pratique avec les assertions, peut être la plus courante, consiste à les utiliser pour vérifier une précondition sur une méthode public.
En effet le contrat ne sera pas vérifié quand les assertions seront désactivées en production, or le programmeur n’a pas le contrôle sur toutes les invocations de la méthode. Dans ce cas il vaut mieux utiliser les exceptions à la place des assertions.
Mauvais pratiques
public float inverseAuCarre (int x) {
assert x == 0 : "Le paramètre est nul";
...
}
NON
Bonnes pratiques
public float inverseAuCarre (int x) {
if (x == 0) {
throw new ArithmeticException("Le paramètre est nul");
}
...
}
Oui!!
Mauvais pratiques
assert connect() : "La connection est impossible";
NON. En effet que se passe-t-il si on désactive les assertions?
Bonnes pratiques
final boolean ok = connect();
assert ok : "La connection est impossible";
mieux!
Mauvais pratiques
assert r1 == r2 : "r1 et r2 devraient être égaux";
NON. Attention à l’égalité entre nombres flottants.
Bonnes pratiques
assert abs(r1 - r2) < 0.0001 : "r1 et r2 devraient être égaux";
mieux!
Tests Unitaires
Maintenant, il est conseillé d’écrire des tests en même temps, voire même avant la méthode à tester (Test Driven Development)
Ici, on s’intéresse au tests unitaires
qui permettent la vérification des fonctions une par une.
Le but est de créer des tests qui permettent d’exécuter le plus d’instructions possibles.
JUnit
Nous allons utiliser le framework JUnit 4
JUnit et les annotations
import org.junit.*;
import static org.junit.Assert.*; // import toutes les fonctions static de la class org.junit.Assert
public class TestFoobar {
@BeforeClass
public void setUpClass() {
// Code exécuté avant l’exécution du premier test
// et de la premiere exécution de la méthode @Before
}
@AfterClass
public void tearDownClass() {
// Code exécuté après l’exécution des tous les tests
}
@Before
public void setUp() {
// Code exécuté avant chaque test
}
@After
public void tearDown() {
// Code exécuté après chaque test
}
@Test
public void test() {
assertTrue(true);
}
}
Assertions JUnit
Avec JUnit, la plus petite unité de tests est l’assertion dont le résultat de l’expression booléenne indique un succès ou une erreur. Il définit une série d’assertion nommées assertXXX()
qui sont héritées de la classe junit.framework.Assert
:
assertTrue()
: vérifie que la valeur fournie en paramètre est vraieassertFalse()
: vérifie que la valeur fournie en paramètre est fausseassertNull()
: vérifie que l’objet fourni en paramètre soit nullassertNotNull()
: vérifie que l’objet fourni en paramètre ne soit pas nullassertSame()
: vérifie que les deux objets fournis en paramètre font référence à la même entitéassertNotSame()
: vérifie que les deux objets fournis en paramètre ne font pas référence à la même entitéassertEquals()
: vérifie l’égalité de deux valeurs de type primitif ou objet (en utilisant la méthode equals())
Exemple
import org.junit.*;
import static org.junit.Assert.*;
public class TestPerson {
private Person p1;
private UPMCPerson p2;
@Before
public void setUp() {
p1 = new Person("alice", 1977) ;
p2 = new UPMCPerson("bob", 1978) ;
}
@After
public void tearDown() {
p1 = null;
p2 = null;
}
@Test
public void testGetName() {
assertEquals("person should have the given name", p1.getName(), "alice");
assertEquals("person should have the given name", p2.getName(), "bob");
}
@Test
public void testEquals() {
assertFalse("different person should be different", p1.equals(p2));
}
}
Exécution de JUnit
javac -cp .:junit-4.XX.jar TestPerson.java
java -cp .:junit-4.XX.jar:hamcrest-core-1.3.jar org.junit.runner.JUnitCore TestPerson
Exemple 2
import org.junit.*;
import static org.junit.Assert.*;
public class SampleTest {
private java.util.List emptyList;
@Before
public void setUp() {
emptyList = new java.util.ArrayList();
}
@After
public void tearDown() {
emptyList = null;
}
@Test
public void testSomeBehavior() {
assertEquals("Empty list should have 0 elements", 0, emptyList.size());
}
@Test(expected=IndexOutOfBoundsException.class)
public void testForException() {
Object o = emptyList.get(0);
}
}
Commentaires et Documentation
Les commentaires
Les commentaires sont des portions du code source ignorées par le compilateur ou l’interpréteur, car ils ne sont pas nécessaires à l’exécution du programme. Ils sont souvent utilisés pour expliquer : la structure code, le fonctionnement des algorithmes, le sens des variables, les optimisations, …
Un commentaire ne doit pas paraphraser le code. Il est inutile si le code est déjà assez clair.
Les Tags
Il existe deux types de tags :
- @tag : les tags standards
- {@tag} : les tags qui seront remplacés par une valeur.
Ces tags peuvent être utilisés pour documenter :
- globalement le programme (fichier overview.html)
- des packages (fichier package.html ou package-info.java)
- des classes et interfaces
- des constructeurs et méthodes
- des attributs
packages, classes et interfaces
Pour documenter les packages, on peut utiliser :
- @author texte : précise le ou les auteur(s)
- @version texte : numéro de version du packages
Pour documenter les classes et interfaces, on peut utiliser :
- @author texte : précise le ou les auteur(s)
- @version texte : numéro de version de l’élément
- @deprecated texte : permet de préciser qu’un élément est déprécié.
Méthodes et constructeurs
- @version texte : numéro de version de l’élément
- @deprecated texte : permet de préciser que la méthode est dépréciée
- @param nom_paramètre description du paramètre : défini un paramètre d’une méthode
- @exception nom_exception description : exception pouvant être levée par une méthode
- @throws nom_exception description : identique à @exception
- @return texte : description de la valeur de retour de la méthode
- {@inheritDoc} : recopie de la documentation de l’entité de la classe mère
I I I I I I I
Les tags génériques
En plus des tags spécifiques aux différents éléments, on peut utiliser :
- @docRoot : chemin relatif de la racine de la documentation
- {@link} : insère un lien vers un élément de la documentation
- {@linkplain} : identique à link dans une police normale
- @see entité : référence à un autre élément
- @since texte : version où l’élément a été ajouté
- {@literal texte} : permet d’insérer plus facilement les caractères spéciaux sans les interpréter
Remarque
Les textes correspondant aux différents tags sont libres, mais les caractères liés au HTML comme < ou > sont interprétés spécialement par javadoc. Pour écrire <, on doit donc utiliser <
.
Génération de la documentation
Pour générer la documentation, on utilise la commande javadoc
suivie d’une liste de fichiers java.
Les options les plus couramment utilisées :
-d <dir>
: permet de choisir le répertoire dans lequel sera générée la documentation ;-author
: permet de prendre en compte les tag @author ;-version
: permet de prendre en compte les tag @version ;-public
: limite la documentation aux classes publiques ;-protected
: limite la documentation aux classes et aux membres publics et protégés (par défaut) ;-package
: limite la documentation aux classes et aux classes et aux membres publics, protégés et ceux accessibles aux classes d’un même package ;-private
: génère la documentation pour toutes les classes et tous les membres.
-encoding
: spécifie l’encodage utilisé dans les sources java.-docencoding
: spécifie l’encodage qui sera utilisé pour générer les fichiers de documentation HTML.-charset
: permet d’ajouter dans le code source HTML l’header Content-Type avec l’encodage spécifié, ce qui permet au navigateur d’utiliser directement le bon encodage.
Pour obtenir une doc HTML en utf8 avec des sources en latin1 :
javadoc -encoding ISO-8859-1 -docencoding utf8 -charset utf8 *.java
Exemple : Documentation d’un package
Depuis Java 5.0 on peut utiliser directement la syntaxe javadoc pour documenter les packages.
Pour cela, il faut ajouter dans le répertoire correspondant au package un fichier package-info.java
qui contient une seule ligne java package <nomPackage> ;
.
/**
* Package contenant un super jeu
* @author Quentin Bramas
* @version 2.0
*/
package supergame;
Exemple : Documentation d’une classe
package supergame ;
/**
* Classe générique pour une IA
* @see wikipedia
* @author Quentin Bramas
* @version 1.00
*/
public class IA {
int pos=0;
/**
* Méthode simulant la course de l'IA
* @param dist distance parcourue par l'IA
* @return retourne la position actuelle
*/
public int courir (int dist) {
return pos += dist ;
}
}
Exemple : Documentation d’une classe
package supergame ;
/**
* Classe d'IA difficile
* @author Quentin Bramas
* @version 1.00
*/
public class IAHard extends IA {
private boolean visible = true ;
/**
* Teste la visibilité de l'IA
* @return true si l'IA est visible
*/
public boolean isVisible () {
return visible ;
}
/** {@inheritDoc} et cache l'IA */
@Override
public int courir (int dist) {
this.hide();
return super.courir(dist);
}
/**
* cache l'IA (du coup elle est vachement difficile à battre)
*/
private void hide() {
this.visible = false;
}
}
Commande javadoc
javadoc -author -private -version -encoding utf8 -docencoding utf8 -charset utf8 -d doc supergame/*.java