Cours sur Java
-------
·
Tout programme Se fonde sur l’utilisation de classes
· Une classe est constituée d’un ensemble d’attributs et d’un ensemble de méthodes
· Un programme construit des instances de classe (objet)
· On peut ranger les classes selon des ensembles : les paquetages. Il y a des règles de visibilité (public, protected, private…) entre les classes et entre les attributs et les méthodes qu’elles contiennent. Ces règles dépendent de l’appartenance ou non à un même paquetage.
Il existe de nombreux paquetages dans le JDK (Java Development Kit)
Vous pourrez en trouver un descriptif dans la documentation fournie en ligne par Sun Microsystems sur le site :
http://java.sun.com/docs
Exemples :
- Le paquetage java.lang contient les classes les plus centrales du langage. Il contient la classe Object qui est la super-classe ultime de toutes les classes. Une classe qui ne déclare pas d’héritage, hérite par défaut de la classe Object.
- Le paquetage java.util définit un certain nombre de classes utiles et est un complément de java.lang.
- Le paquetage java.awt (awt pour Abstract Window Toolkit) contient des classes pour fabriquer des interfaces graphiques.
- Le paquetage java.applet est utile pour faire des applets, applications utilisables à travers le Web.
- Le paquetage java.io contient les classes nécessaires aux entrées-sorties.
- Le paquetage java.net fournit une infrastructure pour la programmation réseau.
Fichiers sources .java (obligatoirement) peuvent contenir plusieurs classes mais au max 1 seule sera publique. S’il y en une : même nom que le fichier.
Compilation : .java => .class : bytecode interprétable par n’importe qu’elle machine virtuelle java (JVM) se conforment à la norme (mais attention à la version de Java).
Il existe des JVM pour à peu près tous les types de machines et tous les systèmes d’exploitation => un programme Java est portable sans recompilation.
II-
Premiers
programmes
HelloWorld
en Java :
class HelloWorld
{
public static void main(String arg[]) {
System.out.println("Bonjour le monde");
}
}
main est toujours définie ainsi. Elle doit être définie dans une classe.
public static :
méthode publique de classe (on n’a pas besoin d’objet pour l’appeler).
String : classe gérant les chaînes de caractères du paquetage java.lang
L'argument de la méthode main est un tableau de chaînes de caractères. Les chaînes contenues dans ce tableau sont les arguments envoyés par la ligne de commande, le nom du programme ne faisant pas partie des arguments (à l’inverse du langage C).
System : classe de java.lang qui fournit des fonctionnalités système indépendantes de la plate-forme d’exécution.
out : flux de sortie standard.
Conventions de nommage : classes Mots en majuscules, méthodes et attributs mots en majuscules sauf le premier qui est toujours en minuscule.
Deuxième programme :
class Somme {
public static void main(String arg[]) {
int
i, somme = 0;
for(i=1 ;
i<=100 ; i++) somme += i ;
// affiche le texte suivi de la valeur de la variable somme
System.out.println("Somme : "+somme) ;
}
}
Similitude avec le C :
Mêmes structures de contrôles ;
Mêmes types de bases (à part boolean) ;
Mêmes opérateurs de comparaison et d’affectation.
III- Définition et utilisation d’une classe
class Ecriture
{
/*chaine est un attribut de la classe Ecriture,
qui doit contenir une reference vers une instance
de la classe String*/
String chaine = "Encore une fois ";
//methode de la classe Ecriture
void ecrire(String autreChaine)
{
System.out.print(chaine);
System.out.println(autreChaine);
}
}
La classe Ecriture a :
- un attribut (notion proche de variable) : chaine (String)
- une méthode (notion proche de fonction) : ecrire
2 catégories de variables :
de type primitif (ex. int) cf exemple précédent.
de type référence destinées à recevoir des adresses d’objets.
Attention : une variable de type référence est similaire à un pointeur en C mais on ne peut pas faire d’arithmétique (par exemple incrémenter un pointeur pour parcourir un tableau) avec les références.
Les types primitifs sont :
le type booléen boolean, qui n'est pas un type entier et qui peut prendre les valeurs false et true
le type caractère char (valeur sur 16 bits pour gérer les caractères asiatiques, arabes…),
les types entiers : byte (8 bits), short (16 bits), int (32 bits) et long (64 bits)
les types réels en virgule flottante : float (32 bits) et double (64 bits)
La valeur par défaut de toute variable ou attribut d'un type "par référence" est la valeur null.
Commentaires : idem C++ (/* */ comme en C et // qui commente une ligne) + commentaires javadoc (pour génération automatique de documentation).
/* commentaire sur plusieurs lignes comme en C
deuxième ligne */
int i = 0 ; // commentaire sur une seule ligne – tout ce qui est derrière le // est en commentaire
/** commentaire javadoc
@param i est un paramètre entier
@return true ou false */
int
methode(int i) {…}
// génère une doc similaire à ce que l’on peut trouver sur le site web de Sun.
Utilisation de la classe : instanciation de la classe Ecrire :
ecrivain = new Ecriture();
Création d’un nouvel objet de la classe Ecriture (allocation de mémoire pour chacun des attributs de la classe et initialisation – ici chaine). new Ecriture(); renvoie une référence qui est stockée dans la variable ecrivain.
Les parenthèses qui apparaissent dans l'instanciation s'expliquent par le fait que l'on fait appel à la méthode Ecriture() de la classe Ecriture appelée le "constructeur" de la classe. Toute classe possède un constructeur. Lorsque le programmeur n'a pas mis explicitement un constructeur, comme c'est le cas ici, le compilateur en ajoute automatiquement un. Dans le cas de la classe Ecriture (pas de constructeur hérité ; cette notion sera développée ultérieurement), le constructeur ajouté est une méthode qui ne fait rien.
Lorsqu'on instancie une classe, on le fait toujours comme ici à l'aide d'un constructeur de la classe.
class PourFeliciter
{
public static void main(String[] arg)
{
Ecriture ecrivain;
ecrivain = new Ecriture();
ecrivain.ecrire("bravo");
ecrivain.chaine = "et pour finir ";
ecrivain.ecrire("au revoir");
}
}
Note : Appel de méthode : variable.methode(parametres);
Accès aux attributs : variable.attribut
IV- Surcharge de méthodes
Java autorise la surcharge de méthodes. C’est à dire qu’on peut avoir plusieurs méthodes de même nom à condition que l’ordre et le type des paramètres soient différents.
Exemple :
class Ecriture
{
String chaine = "Encore une fois ";
void ecrire(String autreChaine)
{
System.out.print(chaine);
System.out.println(autreChaine);
}
void ecrire(int unEntier)
{
System.out.print(chaine);
System.out.println(unEntier);
}
}
A l’exécution java choisira la bonne méthode en fonction des paramètres.
V- Les constructeurs
class Incremente
{
int increment;
int petitPlus;
Incremente(int increment, int petit)
{
this.increment = increment;
petitPlus = petit;
}
Incremente(int increment)
{
this.increment = increment;
petitPlus = 1;
}
int additionne(int n)
{
return (n + increment + petitPlus);
}
}
class UtiliseIncremente
{
public static void main(String[] arg)
{
Incremente monAjout = new Incremente(10, 2);
System.out.println(monAjout.additionne(5));
Incremente monAjout2 = new Incremente(10);
System.out.println(monAjout.additionne(5));
}
}
L'exemple utilise une classe possédant des constructeurs explicites (le choix du constructeur sera fait en fonction de l’ordre des paramètres comme pour la surcharge).
Un constructeur ne retourne pas de valeur mais ne mentionne pas void au début de sa déclaration.
Par ailleurs, un constructeur doit posséder le même nom que celui de sa classe.
Il peut posséder des arguments qui seront initialisés de façon classique.
Les constructeurs de la classe Incremente possèdent un paramètre qui a pour nom increment : celui-ci cache l'attribut increment de la classe Incremente. Le mot réservé this représente, au moment de l'exécution, l'instance de la classe sur laquelle le code est entrain de s'appliquer ; this.increment représente donc l'attribut increment de la classe. L'instruction :
this.increment = increment ;
initialise l'attribut increment de la classe avec la valeur donnée en argument du constructeur. Le problème ne se pose pas avec l'attribut petitPlus et l'argument petit qui ont des noms différents.
VI- Attributs et méthodes de classe (static)
class TestStatic
{
private String nom;
static private int nbInstances;
public TestStatic(String nom)
{
this.nom = nom; nbInstances++;
}
static {
nbInstances = 0 ;
}
public static int getNbInstances() { return
nbInstances; }
public static void main(String[] argv)
{
TestStatic t = new
TestStatic("Un");
TestStatic t1 = new
TestStatic("Deux");
System.out.println(TestStatic.getNbInstances());
System.out.println(TestStatic.nbInstances);
}
}
Une classe peut
posséder des attributs et des méthodes qui existent indépendamment de toute
instance. Ils sont déclarés avec le mot clé static. On les appelle
attributs et méthodes de classe par opposition aux autres attributs et méthodes
appelés attributs et méthodes d’instance car ils s’appliquent à une instance
particulière.
On y accède en les
prefixant par le nom de la classe suivi d’un point.
Ils servent en
général à stocker et travailler sur des informations de l’ensemble des
instances (ici le nombre d’instances, on peut aussi créer un vecteur de toutes
les instances…) ou des méthodes et attributs dont on a besoin avant création
d’objets (ici là méthode main).
L’exemple utilise aussi les mot-clés public / private : public ou privé à la classe. Les attributs privés ne sont pas accessible à l’extérieur de la classe (par exemple par une autre classe). Nous y reviendrons quand nous aborderons les packages.
VII- Les tableaux
Les tableaux ne sont ni des objets, ni des types primitifs. Un tableau se rapproche néanmoins d'un objet par le fait :
- qu'il est manipulé par référence
- qu'il nécessite en général un "new" pour être défini.
class TableauA {
public static void main(String[] argv) {
char[] tableau;
tableau = new char[2];
tableau[0] = 'h';
tableau[1] = 'a';
System.out.println(tableau);
}
}
On obtient à l'exécution :
ha
On peut voir ici une première façon de déclarer et d'allouer un tableau.
char[] tableau;
déclare le tableau tableau, et aurait d'ailleurs aussi pu s'écrire comme en C :
char tableau[];
Par ailleurs, tableau étant déjà défini :
tableau = new char[2];
alloue un tableau pour deux variables de type char.
On pourra remarquer l'utilisation de la méthode println pour un tableau de caractères.
class TableauB {
public static void main(String[] argv) {
boolean tableau[]={true,false,true};
System.out.println("Deuxieme element de tableau : "
+ tableau[1]);
}
}
Voici une façon de déclarer et d'allouer un tableau pour trois variables de type boolean.
Vous pouvez remarquer que la concaténation entre une chaîne de caractères et une variable booléenne, effectuée grâce à l'opérateur "+" est possible. En fait, cela revient à concaténer deux chaînes de caractères car la valeur de la variable booléenne est convertie en une chaîne de caractères par l'opérateur de concaténation.
On a la possibilité de connaître la longueur d'un tableau référencé par la variable tableau en utilisant : tableau.length;
length est en quelque sorte un attribut du tableau, attribut que l'on peut d'ailleurs uniquement lire.
L'exemple suivant a pour objectif de montrer comment manipuler un tableau d'objets, ici un tableau d'Integer. A part pour cela, il n'est pas utile, pour additionner quelques entiers, d'utiliser la classe Integer.
class TableauD {
public static void main(String[] argv) {
Integer tableau[]= new Integer[4];
int somme=0;
for (int i =0;i<tableau.length;i++)
tableau[i]=new Integer(i);
for (int i =0;i<tableau.length;i++)
somme+=tableau[i].intValue();
System.out.println("Somme des entiers : " +somme);
}
}
On obtient à l'exécution :
Somme des entiers : 6
Integer : la classe java.lang.Integer, à consulter comme beaucoup d'autre classes du JDK directement dans la documentation de java, contient beaucoup de méthodes statiques ou non, pour gérer le type int ; à titre d'exemple, la méthode public static int parseInt(String s) convertit la chaîne s en un int.
Le constructeur public Integer(int value) crée une instance de la classe Integer ayant pour attribut (privé) un int de valeur value.
tableau[i]=new Integer(i) : il faut noter que instancier un tableau de trois Integer ne dispense pas de construire une instance d'Integer pour chaque composante du tableau.
tableau[i].intValue(): la méthode utilisée ici est une méthode d'instance de Integer ; elle retourne l'attribut de type int contenu dans l'instance d'Integer invoquée, ici tableau[i].
VIII- Héritage
L'utilisation de l'héritage fait partie intégrante des langages à objets.
Les quelques exemples suivants devraient vous permettre d'acquérir les notions
principales liées à l'héritage en Java.
Soit la classe Rectangle définie ainsi :
class Rectangle {
double
largeur, hauteur;
Rectangle(double
initL, double initH){
largeur=initL;
hauteur=initH;
}
double
perimetre() {return 2*(largeur+hauteur);}
double
surface() {return largeur*hauteur;}
double
diagonale() {
return Math.sqrt(largeur*largeur+hauteur*hauteur);
}
void
doubler() {largeur*=2; hauteur*=2;}
}
Si on veut définir une classe Carré, au lieu de tout redéfinir on peut simplement écrire :
class Carre extends Rectangle {
Carre(double
cote) {
largeur = hauteur = cote;
}
}
Les méthodes de la classe Rectangle seront disponibles automatiquement dans la classe Carré.
Donc on peut écrire :
Rectangle r ;
Carre c ;
r = new Rectangle(3,10);
c = new Carre(4);
System.out.println(“perimetre du
rectangle :”+r.perimetre());
System.out.println(“perimetre du carre :”+c.perimetre());
…
La classe Carre étend la classe Rectangle. On dit aussi, et cela a la même signification, que la classe Carre hérite de la classe Rectangle. On dit encore que la classe Rectangle est la super-classe de la classe Carre. On dit enfin que la classe Carre est une sous-classe de la classe Rectangle.
On peut si on le veut ajouter des attributs et des méthodes supplémentaires à la classe Carre.
Un héritage peut aussi s’exprimer en disant qu’un Carré est un Rectangle (le verbe être étant utilisé pour représenter l’héritage). Et ainsi on peut écrire la chose suivante :
Rectangle r ;
r = new Carre(4);
System.out.println(“perimetre du
rectangle :”+r.perimetre());
…
On peut utiliser le mot clé super pour faire référence à la super-classe ainsi :
class Carre extends Rectangle {
Carre(double
cote) {
super(cote,cote); // appel du constructeur
de Rectangle
}
double perimetre() {
//
on appelle la méthode de même nom de Rectangle
return super.perimetre();
}
public String toString() {
return
“Carré de côté : “+largeur;
}
}
NB : on a aussi surchargé ici la méthode toString de la classe Object.
En effet, en java, toute classe dérive de la classe Object. Si on ne précise pas le mot-clé extends, implicitement on dérive de cette classe (ici Rectangle dérive donc implicitement d’Object).
La classe Object contient une méthode : public String toString(); Cette méthode est utilisée en particulier par :
- l'opérateur de concaténation "+" entre chaînes de caractères ; lorsque un opérande de cet opérateur n'est pas une chaîne de caractères mais un objet, la méthode toString est appliquée à cet objet. Si la méthode toString n'est pas définie dans la classe A de l'objet en question, l'interpréteur cherche dans la classe B dont hérite A. Si la méthode toString n'est pas définie dans la classe B, l'interpréteur cherche dans la classe C dont hérite B et ainsi de suite. Rappelons qu'au sommet de la hiérarchie des classes se trouve la classe Object. Le procédé aboutit donc toujours.
- la méthode : public void println(Object x) de la classe java.io.PrintStream, qui utilise la méthode toString de la classe de x pour écrire celui-ci, en effectuant en fait println(x.toString()); (avec la même technique de remontée que ci-dessus pour la concaténation).
Il peut donc être pratique de redéfinir la méthode toString lorsqu'on crée une nouvelle classe. On doit attribuer le modificateur public pour redéfinir cette méthode car on ne peut pas redéfinir une méthode en diminuant son niveau de visibilité. Nous reviendrons sur les niveaux de visibilité.
En Java une classe ne peut hériter que d’une seule classe. On parle d’héritage simple.
IX- Méthodes et classes Abstraites
Parfois il peut arriver que l’on ne sache pas écrire une méthode mais qu’on veuille la déclarer pour les classes descendantes. On dira dans ce cas que la méthode est abstraite et on la notera avec le mot-clé abstract. Une classe qui a au moins une méthode abstraite sera déclarée abstraite et il sera impossible d’instancier des objets de cette classe.
Par exemple, si on veut définir des classes Disque, Triangle… on pourra avoir pour chacune de ces classes des méthodes périmètre et surface. Donc on peut imaginer vouloir définir une classe GeometriePlane de la façon suivante :
abstract class
GeometriePlane{
public abstract double perimetre();
public abstract double surface();
}
Ensuite, les
autres classes dériveront de GeometriePlane en définissant les méthodes.
class Rectangle extends GeometriePlane {
...
public double perimetre()
{
return
2*(largeur+hauteur);
}
public double surface(){
return
largeur*hauteur;
}
...
}
class Disque extends
GeometriePlane {
static final double PI = 3.1459;
double diametre;
...
public double perimetre() {
return PI*diametre;
}
public double surface() {
return (PI*diametre*diametre)/4;
}
}
On peut voir ci-dessus une utilisation du mot-clé final qui
permet de définir des constantes. Les constantes sont en général définies static
de façon à ce qu’il n’y ait pas une constante par objet.
NB : on peut très bien avoir dans une classe abstraite des attributs et des méthodes non abstraites.
Si on écrit
GeometriePlane g = new GeometriePlane(); on obtient une erreur à la compilation
puisque la classe est non instaciable.
Par contre on peut écrire : GeometriePlane g = new Disque(); et manipuler le disque comme une instance de la classe GeometriePlane.
X- Interfaces
Une classe dont toutes les méthodes sont abstraites peut aussi être définie sous la forme d’une interface. L’intérêt est qu’une classe peut implémenter (c’est le terme qui est utilisé à la place d’hériter dans ce cas là) plusieurs interfaces.
Les interfaces peuvent dériver les unes des autres. Les interfaces peuvent aussi définir des constantes.
interface Geometrie{
public static final double PI=3.14159;
}
interface Courbe extends Geometrie{
public double longueur();
public void doubler();
}
interface Surface extends Geometrie{
public double surface();
}
Les classes Rectangle et Disque peuvent ensuite être décrites de la façon suivante :
class Rectangle
extends Object implements Courbe, Surface {
...
public double perimetre()
{
return
2*(largeur+hauteur);
}
public double surface(){
return
largeur*hauteur;
}
...
}
class Disque extends Object implements
Courbe, Surface {
static final double PI = 3.1459;
double diametre;
...
public double perimetre() {
return PI*diametre;
}
public double surface() {
return (PI*diametre*diametre)/4;
}
}
Les interfaces sont considérées comme des types (mais ne sont pas instanciables) et on pourra donc écrire la chose suivante :
Courbe c;
c = new Disque();
c.perimetre();
Par contre : c = new Courbe(); provoque une erreur de compilation.
En résumé, une classe peut dériver/hériter d’une seule classe et implémenter un nombre quelconque d’interfaces.
XI- Polymorphisme
Le fait de faire hériter plusieurs classes d’une même classe (ou implémenter la même interface) nous permet d’utiliser le polymorphisme pour traiter uniformément un ensemble d’objet de différentes classes.
class TestRectDisk7{
public static void main (String args[]) {
Courbe
c[]=new Courbe[2];
Surface
s[]=new Surface[2];
Rectangle
r =new Rectangle();
Disque d = new Disque();
// un rectangle peut être vu comme une courbe ou une
surface
c[0]=r; s[0]=r;
// idem pour un disque
c[1]=d;
s[1]=d;
//surface de tous les objets
double
surfTotal=0;
for (int
i=0;i<2;i++)surfTotal+=s[i].surface();
//Perimetre de tous les objets
double
periTotal=0;
for (int
i=0;i<2;i++)periTotal+=c[i].perimetre();
}
}
C’est toujours la méthode définie dans la classe qui est réellement instanciée (Rectangle ou Disque) qui est appelée (ou dans la classe ancêtre la plus proche si la méthode n’est pas définie dans la classe d’instanciation).
XII- Paquetages et visibilité
Le concept de paquetage (package en anglais) permet de réunir plusieurs classes dans une même unité logique qui sera représentée par un répertoire sur le disque dur.
On peut aussi définir des sous-paquetages qui correspondent à des sous répertoires.
Dans chaque fichier il faudra écrire : package nom_de_paquetage ; (cette instruction doit être la première du fichier).
Exemple :
package geo;
public
interface Geometrie{
public static final double pi=3.14159;
}
Ou dans le cas d’un sous-paquetage geo d’un paquetage projet :
package projet.geo;
Pour utiliser une classe d’un paquetage à l’intérieur d’un autre paquetage on devra soit :
- préfixer le nom de la classe par le nom du paquetage :
geo.Geometrie g;
- utiliser une directive import :
import geo.Geometrie;
...
Geometrie g;
Les directives import sont placées après la directive package (s’il y en a une) et avant les définitions de classes. On peut utiliser le caractère * pour dire qu’on veut importer toutes les classes et interfaces d’un package :
import
geo.*;
...
Geometrie
g;
Il existe des mots-clés qui permettent de limiter la visibilité des classes, interfaces, méthodes et attributs. Ils sont au nombre de trois (private, protected et public).
Le principe est le suivant :
· Un attribut ou une méthode déclarée private n’est visible que dans sa classe.
· Un attribut ou une méthode déclarée protected n’est visible que dans sa classe, dans les classes du même package et dans les classes dérivées (même si elles ne sont pas dans le même package).
· Un attribut ou une méthode déclarée sans mot-clé (ni private, ni protected, ni public) n’est visible que dans le paquetage dans lequel est définie sa classe.
· Un attribut ou une méthode déclarée publique est visible de toute classe.
D’autre part :
· Une classe déclarée publique est visible dans tout paquetage.
· Une classe qui n’est pas déclarée publique n’est visible que dans son paquetage.
XIII- Exceptions
Une exception correspond à un événement anormal ou inattendu. Les exceptions
sont des instances de sous-classes des classes java.lang.Error (pour des erreurs
graves, qui devront généralement conduire à l'arrêt du programme) et java.lang.Exception
(pour des événements inattendus, qui seront souvent traités de sorte qu'elle ne
provoque pas l'arrêt du programme).
Un grand nombre d'exceptions sont définies dans l'API et sont
"lancées" par des méthodes de l'API.
Les exemples suivants montreront comment on définit ou comment on lance une
exception. Nous nous contentons ici d'en attraper une (une instance de java.lang.NumberFormatException),
et d'en laisser passer une autre (une instance de java.lang.ArithmeticException).
Lorsqu'une exception est lancée, elle va se propager de la façon décrite ci-dessous. Nous supposons que l'exception est lancée par une certaine instruction I d'une méthode de nom uneMethode. L'explication que nous donnons est récursive.
Alors :
Si une exception est lancée et pas attrapée, et donc qu'elle provoque la terminaison du programme, la pile des méthodes traversées par l'exception est indiquée à l'utilisateur.
Une méthode susceptible de lancer une exception sans l'attraper (c'est-à-dire
contenant une instruction susceptible de lancer une exception sans que celle-ci
soit attrapée à l'intérieur de la méthode) doit l'indiquer dans son en-tête,
nous verrons la syntaxe correspondante dans un prochain exemple. Néanmoins, on
est dispensé d'indiquer la possibilité de lancement des erreurs les plus
courantes, comme par exemple java.lang.ArrayIndexOutOfBoundsException.
class ExceptionCatch
{
static int moyenne(String[] liste)
{
int somme = 0,entier, nbNotes = 0;
for (int i = 0; i < liste.length;i++)
{
try
{
entier = Integer.parseInt(liste[i]);
somme += entier;
nbNotes++;
}
catch (NumberFormatException e)
{
System.out.println("La "+(i+1)+" eme note "+
"n'est pas entiere");
}
}
return somme/nbNotes;
}
public static void main(String[] argv)
{
System.out. println("La moyenne est " + moyenne(argv));
}
}
Pour :
Java
ExceptionCatch ha 15 12 on obtient en sortie
La 1 eme note n'est pas entiere
La moyenne est 13
et pour : java ExceptionCatch ha 15.5
La 1 eme note n'est pas entiere
La 2 eme note n'est pas entiere
java.lang.ArithmeticException: / by zero
at ExceptionCatch.moyenne(ExceptionCatch.java:22)
at ExceptionCatch.main(ExceptionCatch.java:27)
Pour accéder au programme.
Si on veut pouvoir signaler un événement exceptionnel d'un type non prévu par l'API, il faut étendre la classe java.lang.Exception ; la classe étendue ne contient en général pas d'autre champ qu'un (ou plusieurs) constructeur(s) et éventuellement une redéfinition de la méthode toString. Lors du lancement de l'exception, (à l'aide du mot réservé throw comme nous le verrons dans le prochain exemple), on crée une instance de la classe définie.
Voilà une classe héritant de la classe Exception que nous utiliserons dans les deux exemples suivants.
class
ExceptionRien extends Exception {
public String toString() {
return("Aucune note n'est valide");
}
}
Pour cet exemple et le suivant, l'objectif est de calculer une moyenne de notes entières envoyées en arguments par la ligne de commande. Les arguments non entiers (et donc erronés) doivent être éliminés.
On utilise l'exception ExceptionRien.
class
ExceptionThrow {
static int moyenne(String[] liste) throws ExceptionRien {
int somme=0,entier, nbNotes=0;
int i;
for (i=0;i < liste.length;i++) {
try {
entier=Integer.parseInt(liste[i]);
somme+=entier;
nbNotes++;
}
catch (NumberFormatException e) {
System.out.println("La
"+(i+1)+" eme note n'est "+
"pas
entiere");
}
}
if (nbNotes==0) throw new ExceptionRien();
return somme/nbNotes;
}
public static void main(String[] argv) {
try {
System.out.println("La moyenne est "+moyenne(argv));
}
catch
(ExceptionRien e) {
System.out.println(e);
}
}
}
Pour : java ExceptionThrows ha 15.5, on obtient :
La 1 eme note n'est pas entiere
La 2 eme note n'est pas entiere
Aucune note n'est valide
throws ExceptionRien : la méthode moyenne indique ainsi qu'il est possible qu'une de ses instructions envoie une exception de type ExceptionRien sans que celle-ci soit attrapée par un mécanisme try-catch. Il est obligatoire d'indiquer ainsi un éventuel lancement d'exception non attrapée, sauf pour les exceptions les plus courantes de l'API. Si vous oubliez de signaler par la clause throws l'éventualité d'un tel lancement d'exception, le compilateur vous le rappelera.
throw new ExceptionRien() : on demande ainsi le lancement d'une instance de ExceptionRien. Une fois lancée, l'exception se propagera comme expliqué dans l'exemple précédent. Ici, il y aura sortie de la méthode moyenne, on se retrouve alors à l'appel de la méthode moyenne dans le main, appel qui se trouve dans un "bloc try" suivi d'un "bloc catch" qui attrape les ExceptionRien(s) : l'instruction de ce "bloc catch" est effectuée. Le programme reprend alors son cours normal (pour se terminer).