Compléments pour bien démarrer #
Classes utilitaires, classes exécutables #
Nous parlons de classes “utilitaires” lorsqu’elles offrent des fonctionnalités statiques. La classe Math
de Java en est un bon exemple.
|
|
Nous avons vu l’exemple du HelloWorld
qui permettait d’exécuter un programme Java. Une application est généralement composée de package
s1, classes, interfaces, … Une convention veut qu’il n’existe qu’un type public (visible à l’utilisateur2) par fichier. Parmi ceux-ci, il est nécessaire d’avoir une classe qui réalise l’amorce du programme, appelé classe principale ou programme principal : le main
. Celui-ci est également appelé ainsi dans d’autres langages.
En Java, le programme principal est une classe. Pour indiquer qu’elle est exécutable, elle doit comporter une méthode main
dont la signature3 est donné ci-dessous. Nous avons nommé cette classe MainApp
. Depuis celle-ci, nous appelons nos fonctionnalités écrite dans un autre fichier se situant dans le même répertoire appelée MathUtil
(pour ne pas rentrer en conflit avec la classe Math
existante).
La classe utilitaire:
|
|
La classe exécutable:
|
|
Vous remarquez que toutes les méthodes sont statiques puisqu’elles sont rattachées à la classe MathUtil
et non à un objet instancié. Comme nous l’avons déjà mentionné ici
, cela permet d’écrire des fonctions sans faire de POO.
Compiler et exécuter (les dépendances se compileront automatiquement):
|
|
Lecture et affichage dans le terminal #
Affichage dans le terminal #
La classe System
met à disposition le flux de sortie out
et fournit plusieurs méthodes
print
: affichage sans retour à la ligneprintln
: avec retour à la ligneformat
: correspond auprintf
du C- et plein d’autres4
|
|
Lecture d’une entrée utilisateur #
La lecture d’une entrée utilisateur se fait à l’aide de la classe Scanner
et du flux d’entrée Scanner.in
. La méthode nextInt()
peut retourner une exception si l’utilisateur entre une valeur non entière.
|
|
Classes enveloppes #
Chaque type primitif a son équivalent en terme de classe.
type primitif | Classe associée (classe enveloppe) |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
L’autoboxing est la conversion automatique d’un type primitif en un objet. Le “unboxing” est l’opération inverse.
// Autoboxing:
Integer i = 3; // au lieu de Integer i = new Integer(3); (déprécié)
// Unboxing
int j = i;
Attention
Préférez toujours les types primitifs. Rappelez-vous que les paramètres d’un type générique ne peuvent pas être un type primitif (
List<Integer>
et nonList<int>
). C’est souvent la seule situation où les classes envoloppes sont employées.Les classes enveloppes se trouvent sur le tas, elles sont donc moins performantes que les types primitifs qui se trouvent sur la pile. De plus, un
byte
possède 256 valeurs possibles alors que l’équivalentByte
en possède 257 (256 + null puisqu’il s’agit d’une référence).// Danger jshell> Byte b; ==> null // et non 0 !
Il existe cependant des méthodes statiques intéressantes. En voici quelques exemples:
int i = Integer.parseInt("42"); /* ==> retourne une exception si la chaîne
comporte des caractères non numériques */
short s = Short.MAX_VALUE; // ==> 32767
boolean isDigit = Character.isDigit('.'); // ==> false
Nombres à précision arbitraire #
Nous avons déjà vu un exemple de la classe BigDecimal
qui permet une représentation arbitraire
pour les nombres décimaux. Une telle classe existe pour les entiers : BigInteger
.
Exceptions (notions de base) #
Une exception est un mécanisme de gestion d’erreurs qui peut être levée lorsqu’un appel de méthode ou une expression est dans un état instable. Les arguments passés en paramètres de la fonction ne respectent pas le contrat, le programme tente de lire un fichier inexistant, récupération d’un élément dans une liste à un indice plus grand que la taille de cette liste, …
|
|
Un chapitre sera dédié aux exceptions et à l’absence de valeur. Pour l’instant, cette section explique quelques notions de bases.
Provoquer une exception #
Pour l’instant, si vous réalisez une fonctionnalité qui ne peut pas retourner un résultat cohérent, vous pouvez retourner l’exception RuntimeException
avec un message, précédé du mot-clé throw
. Ne retournez pas l’exception Exception
.
|
|
Traiter une exception #
Il est possible de contrôler une exception. Pour l’instant, si une méthode vous oblige à traiter l’exception, vous pouvez indiquer que la méthode et la méthode main
peut lever une exception avec le mot-clé throws
dans la signature desdites méthodes.
L’exemple ci-dessous permet de lire une entrée de l’utilisateur, de l’écrire dans un fichier, puis d’afficher le contenu lu dans le fichier.
|
|
Le mot-clé
assert
permet de vérifier qu’une condition soit toujours vraie. Une assertion fausse termine le programme avec l’exceptionAssertionErrors
qui ne peut pas être traitée. Son utilisation se retrouvera dans beaucoup d’exemples.Les assertions ne sont pas vérifiées par défaut. Un paramètre spécifique lors de l’exécution est nécessaire:
javac WriteToFile.java java -ea WriteToFile
Une deuxième façon, plus traditionnelle, consiste à gérer l’exception dans un bloc dédié à cet effet : Le bloc try ... catch
:
try {
int i = scanner.nextInt(); /* l'utilisateur ne rentre pas forcément en entier
==> exception InputMismatchException est retournée */
System.out.println(i);
} catch (InputMismatchException e) { // traitée ici
System.err.println(e.toString()); // affichage de l'erreur sur stderr
} finally { // finally = "dans tous les cas..."
scanner.close(); // ... il est nécessaire de fermer le scanner
}
Rappelons qu’un chapitre sera dédié aux exceptions.