Première partie

Objective d’apprentissage

  • Comprendre la différence entre les exceptions à déclaration obligatoire et à déclaration non obligatoire (« checked » et « unchecked »)
  • Définir l’usage des mots clé try, catch, finally, throw, et throws.
  • Implémenter vos propres exceptions

Exceptions:

Les exceptions sont des « problèmes » qui surviennent lors de l’exécution d’un programme. Quand une exception survient, le flot d’exécution du programme est interrompu, et si l’exception n’est pas gérée, le programme se terminera.

Certaines exceptions sont causées par des erreurs commises par l'utilisateur, d'autres par celles des programmeurs ou parfois il s'agit d'un problème du côté des ressources physiques.

Quelques exemples d’exceptions sont :

  • Un usager entre une valeur invalide
  • Un fichier à ouvrir n’est pas trouvé

Il y a deux types d’exceptions : les exceptions à déclaration obligatoire et les exceptions à déclaration non obligatoire.

Exceptions à déclaration obligatoire (« Checked exceptions »)

Une exception à déclaration obligatoire, aussi connu sous le nom de « checked exception », est une exception qui sera vérifier par le compilateur. Ces exception ne peuvent pas être ignoré et doivent explicitement être traiter par le programmer, nous verrons comment plus tard.

Un exemple d’exception à déclaration obligatoire est l’exception FileNotFoundException. Lorsque l’on tente d’utiliser un FileReader, (nous explorerons les FileReader dans un autre laboratoire; ils sont utilisés pour lire le contenu d’un fichier) si le fichier spécifié dans le constructeur du FileReader n’existe pas, nous obtiendront l’exception FileNotFoundException.

import java.io.File;
import java.io.FileReader;

public class FilenotFound_Demo {

   public static void main(String args[]) {		
      readFile();
   }
   public static void readFile(){
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file); 

   }
}
  

Si vous tentez de compiler ce code, vous obtiendrez ce message :

FilenotFound_Demo.java:11: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error
  

Les exceptions à déclaration non obligatoire (« unchecked exceptions »):

Les exceptions à déclaration non obligatoire, aussi connu sous le nom de « unchecked exceptions » sont des exceptions qui ne requière pas être explicitement traiter par le programmer. Elles incluent les bugs, les erreurs de logiques ainsi que les mauvaises utilisations d’un « API ».

Un exemple d’exception à déclaration non obligatoire avec lequel vous être probablement déjà familier est l’exception ArrayIndexOutOfBoundsException qui survient lorsque vous tentez d’accéder à l’index d’un tableau qui est à l’extérieur de ses frontières.

public class ArrayOutOfBound_Demo {

   public static void main(String args[]) {		
      createArray();
   }
   public static void createArray(){
      int[] myArray=new int[2];
      myArray[2]=1;

   }
}
  

Si vous tentez de compiler ce code, vous pourrez le faire sans problèmes. Par contre, quand vous tentez d’exécuter le code, vous obtiendrez ce message :

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
        at ArrayOutOfBound_Demo.createArray(ArrayOutOfBound_Demo.java:8)
        at ArrayOutOfBound_Demo.main(ArrayOutOfBound_Demo.java:4)
  

Voici une hiérarchie des erreurs et exceptions en Java:

Hiérarchie des erreurs et exceptions en Java Figure 1 : Hiérarchie des erreurs et exceptions en Java

Throw et Throws:

Si une méthode ne gère pas une exception à déclaration obligatoire, on doit déclarer à la fin de la définition de la méthode qu’elle peut lancer une exception, ainsi que du type d’exception en question. Cela se fait par l’utilisation du mot clé throws. Lorsque vous lancez une exception, soit en créant une nouvelle exception ou en lançant une exception qui a été attrapée, vous devez utiliser le mot clé throw.

Il est important de comprendre que :

  • Mot clé throws : se trouve dans la déclaration de la méthode et indique que la méthode peut lancer une exception à déclaration obligatoire suivie du type d’exécution en question. Facultativement, on peut indiquer quelle exception à déclaration non obligatoire seront tirer.
  • Mot clé throw : est utilisé pour lancer une exception, que ce soit une exception à déclaration obligatoire ou à déclaration non obligatoire.

Lancer une exception signifie que le flot du programme est interrompu et que l’exception est retourné à la méthode ayant appelé cette méthode, et ce, récursivement jusqu’à ce que l’exception soit attrapée.

Une méthode peut avoir plusieurs throws; il suffit de les séparer par une virgule comme ceci :


public void myMethod() throws ExceptionA, ExceptionB{
//some code
}

Try, Catch et Finally:

Tout code qui est susceptible de causer une exception devrait être entouré par un block try. Un block try doit être suivi par un block catch. Si une exception survient et est lancé lors de l’exécution du block try, elle sera attrapée par le block catch associé avec ce type d’exception.

Un block catch implique que le type de l'exception que nous essayons d'attrapée soit déclaré. Si l'exception que notre block catch essaie d'attrappée est lancée, c'est le code qui se trouve dans ce block qui sera immédiatement exécuté (et non le reste de notre block try). Les block catch suivent donc toujours un block try. Il peut aussi y avoir un ou plusieurs blocks catch, mais sachez qu'un seul sera exécuté!

Conseil: uniquement le premier block catch qui correspond à l'exception lancée sera exécut.. Il est donc important que vous placiez toujours vos blocks catch en ordre du plus scécifique au moins spécifique

Un block finally ssera toujours exécuté après une déclaration try-catch qu'il y ait ou non eu une exception lancée ou attrappée.

Dans l'exemple suivant, nous essayon (try) d'exécuter la méthode throwingMethod, qui lance (throws) IOException. Lorsque l'exception est lancée, elle est attrappée la méthode main avec la déclarationcatch. Puisque la IOException est une checked exception, la signature de la méthode throwingMethod se doit de terminer avec le mot-clé throws accompagné du type de l'exception (IOException dans notre cas)

import java.io.IOException;
public class TryCatchThrow_Demo {

   public static void main(String args[]) {		
      try{
	System.out.println("start the try block");
	throwingMethod();
      }
      catch(IOException e){
	System.out.println("The exception is caught");
      }
   }

   public static void throwingMethod() throws IOException{
	//some code...
      System.out.println("Running the method throwingMethod");
      throw new IOException();
   }
}
  

Après l'exécution du code, nous obtenons:

start the try block
Running the method throwingMethod
The exception is caught
  

Dans le prochain exemple, on peut voir que nous n'avons pas besoin d'utiliser le mot-clé throws, car il s'agit d'une unchecked exception. Nous utilisons aussi deux blocks catch, soit un pour gérer une exception spécifique et un autre pour attraper et définir d'une manière par défaut à n'importe quelles autres exceptions. catch(Exception e) attrapera toutes les exceptions car elles sont tous des enfant de Exception.Nous avons aussi une déclaration avec finally qui sera toujours exécutée.

Rappel: l'exception la plus spécifique doit être placée en premier!

public class ArrayOutOfBound2_Demo {

   public static void main(String args[]) {		
      try{
	System.out.println("start the try block");
	createArray();
      }
      catch(ArrayIndexOutOfBoundsException e){
	System.out.println("The specific exception is caught");
      }
      catch(Exception e){
	System.out.println("the generic Exception is caught");
      }     
      finally{
	System.out.println("Executing the finally block");
      }
   }
   public static void createArray(){
      int[] myArray=new int[2];
      myArray[2]=1;
      
   }
}
  

En exécutant ce code, on obtient:

start the try block
The specific exception is caught
Executing the finally block
  

Essayez d'inverser l'ordre des blocks catch et voyez ce qui se produit!

Exercice 1

Complétez le code suivant afin qu'il compile et que vous attrapiez chaque type d'exceptions lancé par la méthode randomException. Imprimez le type de l'exception ainsi que le exceptionNumber générez aléatoirement.

import java.io.IOException;

public class Exercice1{

   public static void main(String args[]) {		
      try{
	randomException();
      }
   }
   
   public static void randomException(){
      int exceptionNumber=(int)(Math.random()*5) + 1;
      if(exceptionNumber==1){
	throw new Exception(); 
      }
      if(exceptionNumber==2){
	throw new ArrayIndexOutOfBoundsException(); 
      }
      if(exceptionNumber==3){
	throw new IOException(); 
      }
      if(exceptionNumber==4){
	throw new IllegalArgumentException(); 
      }
      if(exceptionNumber==5){
	throw new NullPointerException(); 
      }      
   }
}
  

Exécutez le code quelques fois devraient vous donner des résultats similaires à :

>java Exercice1
The exception type is: ArrayIndexOutOfBoundsException, the exceptionNumber is :2

>java Exercice1
The exception type is: ArrayIndexOutOfBoundsException, the exceptionNumber is :2

>java Exercice1
The exception type is: Exception, the exceptionNumber is :1

>java Exercice1
The exception type is: IOException, the exceptionNumber is :3

>java Exercice1
The exception type is: NullPointerException, the exceptionNumber is :5
  

Créer des exceptions:

Les exceptions sont des classes; elles contiennent des méthodes et des variables tout comme les classes habituelles. just like any other class. Toutes les exception doivent être enfant de Exception. Pour créer des exception à déclaration obligatoire (checked), vous devez dériver de la classe Exception, tandis que pour les exception à déclaration non obligatoire (unchecked) vous devez dériver de la classe RuntimeException.

Par exemple, nous voulons parfois lancer une exception si un nombre négatif est donné. Nous créerions donc la classe NegativeNumberException.

public class NegativeNumberException extends Exception{
	private int number;
	public NegativeNumberException(int number){
		super("Cannot us a negative number: "+ number);
		this.number=number;
	}
	public int getNumber(){
		return number;
	}   
}
  

Note : l’appelle au super constructeur permettra a la méthode par défaut getMessage de retourner le String mis en paramètre. Il existe plusieurs autres méthodes hériter de la classe Exception incluant toSting

Cette nouvelle exception créée peut maintenant être utilisée comme une exception régulière.

public class NegativeNumberException_Demo{
   

   public static void main(String args[]) {		
      try{
	printSquareRoot(4);
	printSquareRoot(-1);
      }
      catch(NegativeNumberException e){
		System.out.println(e.getMessage());
		System.out.println("the number " + e.getNumber() + " is invalid");
      }
      
   }
   public static void printSquareRoot(int x) throws NegativeNumberException{
	if(x<0){
	   throw new NegativeNumberException(x);
	}      

	System.out.println("the square root of " + x + " is "+Math.sqrt(x));
      
   }
}
  

En exécutant ce code, on obtient:

the square root of 4 is 2.0
Cannot us a negative number: -1
the number -1 is invalid
  

Exercise 2:

Pour cet exercice, vous devez créer une classe nommée Account. Cette classe représente un compte de banque. Elle possède un constructeur qui initialise la variable balance à 0. La classe possède aussi deux méthodes: deposit qui reçoit en paramètre un nombre de type double et ajoute cette valeur à la balance du compte et la méthode withdraw (retrait) qui reçoit elle aussi un nombre de type double, mais cette fois retire ce montant de la balance du compte.Les deux méthodes devrait imprimer le nouveau montant du compte. Attention, si le montant à retirer est supérieur à la balance du compte, vous devrez lancer l'exception NotEnoughMoneyException. Cette exception que vous créerez doit dériver de la classe IllegalStateException, elle possède une méthode getAmount qui retourne le montant qui a été demandée d'être retiré, getBlance qui retourne le montant du compte au moment de création de l’exception et getMissingAmount qui retourne le montant manquant pour pouvoir effectuer le retrait. L’exception devrait aussi invoquer son super constructeur afin que la méthode getMessage puisse donner un message indiquant que le montant ne peut pas être retiré.

public class Exercice2{
   

   public static void main(String args[]) {
	try{
	   Account myAccount=new Account();
	   myAccount.deposit(600);
	   myAccount.witdraw(300);
	   myAccount.witdraw(400);
	}
	catch(NotEnoughMoneyException e){
	   System.out.println(e.getMessage());
	   System.out.println("You are missing " + e.getMissingAmount() + "$");
	}
   }

}	
  

Lorsque vous exécuterez votre programme, vous devriez avoir une sortie similaire à ceci:

new balance=600.0$
new balance=300.0$
you have not enought money to witdraw 400.0$
You are missing 100.0$
  

 

Deuxième partie

Objective d’apprentissage

  • Comprendre l’interprétation des programmes informatique
  • Définir, lancer et attraper des exceptions Java
  • Étendre un interpréteur (machine virtuelle) basé sur une pile.

Luka : un langage de programmation simple

Contexte

Dans cet exercice, nous explorerons l’interprétation des programmes en utilisant un langage simple de programmation nommé Luka. Ce langage est nommé en l’honneur du mathématicien polonais Jan Łukasiewicz qui a introduit la Notation polonaise inverse (Reverse Polish Notation, RPN). Luka est un langage basé sur les piles inspiré par PostScript1. Son interpréteur scan un programme de la gauche vers la droite, pousse (push) et retire (pop) les opérandes de la pile pendant l’évaluation du programme. Le langage Luka contient plusieurs opérations pour dessiner sur une surface en deux dimensions. Le résultat d’une exécution Luka est généralement un dessin.

Des programmes Luka simple

  • Voici les fichiers dont vous aurez besoin pour le programme Luka : Luka.zip

Premièrement, familiarisons-nous avec la syntaxe des programmes Luka simple. Lancez l’interpréteur en exécutant la classe Java Run. Entrez un programme simple comme celui-ci.

9 2 4 mul 5 sub div pstack

Notez l’expression RPN des notes de lectures : "9 2 4 × 5 - /". A la première itération, l’interpréteur lit et pousse 9 sur la pile des opérandes, à la deuxième et troisième itération, l’interpréteur pousse 2 puis 4 sur la pile des opérandes. A la quatrième itération, l’interpréteur lit le symbole « mul » et appelle la méthode execute_mul(). La méthode retire les deux opérateurs du dessus de la pile (4 puis 2), multiplie le premier avec le deuxième, et enregistre le résultat sur la pile. Le programme se termine quand la pile des opérandes ne contient qu’un élément, dans ce cas la valeur 3. L’exécution de ce programme imprime ceci à la console.

DynamicArrayStack: {3}

Comme avec d’autres programmes Java, vous pouvez utiliser des méthodes pour imprimer le progrès de votre programme Luka :

9 pstack 2 pstack 4 pstack mul pstack 5 pstack sub pstack div pstack

Exécuter le programme ci-dessus et vous obtiendrez ce résultat :

DynamicArrayStack: {9}  
DynamicArrayStack: {2,9}  
DynamicArrayStack: {4,2,9}  
DynamicArrayStack: {8,9}  
DynamicArrayStack: {5,8,9}  
DynamicArrayStack: {3,9}  
DynamicArrayStack: {3}

Assurez-vous d’essayer des programmes Luka qui produisent des résultats graphiques (de dessins)! Ici, l’opération def est utilisé pour créer une association entre la valeur et un symbole:

/x 100 def 
/y 300 def 
x y moveto 
y y lineto
x x lineto 
x y lineto

Essayez d’exécuter les autres exemples fournis dans le fichier zip Luka fournie plus haut (soit prog-01.luka, prog-02.luka et prog-03.luka).

Exercises

Dictionary

Changer la classe Dictionary afin d’inclure des exceptions pour que tous les tests de la classe DictionaryTest passent avec succès. Par exemple, la méthode put dans la classe Dictionary devrait inclure la gestion d’exceptions suivante:

public void put(String key, Token value) {

	if (key == null || value == null) {
		throw new NullPointerException("key or value is null");
	}

	if (count == elems.length) {
		increaseCapacity();
	}

	// Similarly to the array-based implementation
	// of a stack, I am adding elements at the end
	elems[count] = new Pair(key, value);
	count++;
}

LukaSyntaxException

  • Définissez une nouvelle exception d’exécution nommée LukaSyntaxException.
  • Faites les changements à la classe Interpreter pour qu’une exception de type LukaSyntaxException soit lancée lorsque l’une des situations suivantes se produit :
    • Lorsqu’un symbole illégal est trouvé. Un symbole illégale est un symbole quin'est ni un mot clé réservé (opération), ni une association existante dans le dictionnaire. (Note : ni est un opérateur qui donne la valeur un si et seulement si tous les opérandes ont une valeur de zéro, sinon il donne la valeur zéro.)
    • Quand l’on retire la définition (undefining) une association non-existante
    • Quand on fait la mise à jour d’une association non-existante
  • La classe Interpreteur va imprimer le message approprié, incluant :
    • La table des symboles
    • La pile des opérandes.
  • Faites des changements à la classe Viewer pour que l’exception de type LukaSyntaxException soit attrapée. Lorsque vous attrapez l’exception, la méthode imprime le type d’exception et son message. Finalement, l’application se termine.

Par exemple, après l’exécution du programme Luka suivant :

/x 1 def /y 2 def x y /z 3 set

L’application imprimera cette information puis se terminera.

LukaSyntaxException: 
Dictionary: {elems = [{key=y,value=2}, {key=x,value=1}]}
DynamicArrayStack: {3,z,2,1}
ILLEGAL SYMBOL: set
caught LukaSyntaxException

Bonus : testez vos talents artistiques!

Dessinez un carré en utilisant les valeurs et opérations suivantes :

Utiliser seulement la valeur 100 associer au symbole /x :

  • /x 100 def

Ainsi que les trois opérations suivantes :

  • moveto: Positionne le crayon aux coordonnées (x′,y′).
  • lineto: Dessine une ligne de (x,y) a (x′,y′), où (x,y) est la position actuelle
  • add: Retire les deux éléments du dessus de la pile des opérandes, les additionne ensemble et pousse le résultat sur la pile.

1. PDF (Portable Document Format) est largement basé sur PostScript, PostScript et PDF sont des marque déposée de AdobeSystems Incorporated.

 

Troisième partie

Quiz (1 point)

public class Quiz{
   

   public static void main(String args[]) {
	try{
	   quizMethod();
	}
	catch(CostumException e){
	   System.out.println("the exception is caught");
	}
   }
   public static void quizMethod(){
	throw new CostumException();
   }
}	
  
  1. est une exception à déclaration obligatoire (Checked)
  2. est une exception à déclaration non obligatoire (Unchecked)
  3. ce code ne compilera pas
  4. aucune de ces réponses
Réponses :
  

Soumettez la réponse sur Brightspace.

 

Table of Contents