Défi
Dans cet exercice, nous allons concevoir un programme Java robuste qui couvre tous les aspects de la conception du code de gestion des exceptions.
Imaginons un programme mettant en œuvre les fonctionnalités de base des distributeurs automatiques de billets dans la région de Montpellier.
Une des règles fondamentales que le programme doit implémenter est que l'on ne puisse pas retirer de l'argent dont le montant dépasse le solde bancaire du compte courant.
On a proposé un code qui fait ce qui lui est demandé et ne fait rien lorsque lorsque l'on veut retirer un montant supérieur à celui du compte courant.
Le Team Manager a donc décidé de vous confier la responsabilité de corriger les erreurs du programme car il sait que vous avez suivi notre cours d'exceptions.
Votre défi est donc de corriger le programme suivant et également d'utiliser les bonnes pratiques du mécanisme de gestion des exceptions proposé par Java afin que le programme puisse fonctionner à nouveau et implémenter correctement la règle sur les retraits.
Question
Vous trouverez ci-dessous le programme Java contenant une classe représentant un compte bancaire lambda dans lequel les utilisateurs peuvent afficher, déposer ou retirer de l'argent.
Le code ci-dessous est utilisé pour enregistrer les transactions et ne fait rien lorsqu'un utilisateur essaie de retirer un montant supérieur à celui qu’il a dans son compte.
Nous avons donc trois problèmes :
Comment gérer les exceptions
Comment utiliser le mécanisme d'exceptions pour implémenter le signalement à l'utilisateur qu'il ne doit retirer qu'un montant inférieur à celui qu'il a sur son compte.
Gérer les ressources utilisées correctement et capturer les exceptions qu'on va lever afin que le programme puisse fonctionner correctement.
import java.util.Scanner;
public class Compte {
private int solde = 100;
public static void main(String[] args) throws InterruptedException {
Compte compte = new Compte();
System.out.println("""
Bonjour et Bienvenue dans notre banque
\tTapez 1 ==> Vérifiez le solde de votre compte
\tTapez 2 ==> Faire un dépôt
\tTapez 3 ==> Faire un retrait
\tTapez 4 pour enregistrer les opérations effectuées et quitter l'application """);
Scanner sc = new Scanner(System.in);
boolean isWrongAnswer = true;
while (isWrongAnswer) {
System.out.println("*********************************************************************************");
System.out.println("Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:");
switch (sc.nextInt()) {
case 1 -> compte.soldeActuel();
case 2 -> {
System.out.println("Entrez le montant du dépôt");
compte.depot(sc.nextInt());
}
case 3 -> {
System.out.println("Entrez le montant du retrait");
compte.retrait(sc.nextInt());
}
case 4 -> {
System.out.println("Opération(s) enregistrée(s)! Au revoir");
Thread.sleep(2000);
isWrongAnswer = false;
}
default -> {
System.out.println("Tapez uniquement les nombres entre 1 et 4");
}
}
}
}
/* Le solde doit toujours être positif */
public int getSolde() {
return solde;
}
/* Le montant à retirer doit toujours être > le solde actuel */
public void retrait(int montant) {
this.solde -= montant;
soldeActuel();
}
public void depot(int montant) {
this.solde += montant;
soldeActuel();
}
public void soldeActuel() {
System.out.println("Le solde du compte courant est de " + this.getSolde() + " euros");
}
}
C:\>javac Compte.java
java: unreported exception java.lang.InterruptedException; must be caught or declared to be thrown
Nous devons donc traiter tous les problèmes liés à ce programme en utilisant le mécanisme de gestion des exceptions Java que nous avons appris dans le cours.
Indice
1. Le compilateur affiche une exception de type InterruptedException.
La plupart des classes et méthodes intégrées au langage Java sont codées de façon à gérer les exceptions qu'elles peuvent générer. Et leurs exceptions sont dites vérifiées.
Nous allons donc ici soit gérer l'exception InterruptedException générée par la méthode sleep( )
de la classe Thread (classe intégrée du langage Java), soit la propager (la spécifier).
public static void main(String[] args) throws InterruptedException { ... }
Nous avons donc ajouté la spécification de l'exception InterruptedException dans la déclaration de la méthode main( )
à l'aide du mot-clé throws afin de la propager et de déléguer son traitement à une méthode située plus haut dans la liste des appels de méthode.
C:\>javac Compte.java
Bonjour et Bienvenue dans notre banque
Tapez 1 ==> Vérifiez le solde de votre compte
Tapez 2 ==> Faire un dépôt
Tapez 3 ==> Faire un retrait
Tapez 4 pour enregistrer les opérations effectuées et quitter l'application
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
1
Le solde du compte courant est de 100 euros
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
3
Entrez le montant du retrait
250
Le solde du compte courant est de -150 euros
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
4
Opération(s) enregistrée(s)! Au revoir
Process finished with exit code 0
Le code compile, cependant, on voit bien que l’on a effectué un retrait de 250 euros sur un compte au solde de 100 euros. Après cette opération, le solde affiche -150 euros
Pour corriger cela, il ne reste plus qu'à mettre en place la gestion de la règle sur les retraits d'argent.
Indice
2. L’implémentation de cette règle peut se faire par un mécanisme de gestion d’exception personnalisée.
Nous allons créer une exception personnalisée appelée MontantSoldeDoitEtreSuperieurAuMontantRetraitException.
class MontantSoldeDoitEtreSuperieurAuMontantRetraitException extends Exception {
private String message;
public MontantSoldeDoitEtreSuperieurAuMontantRetraitException(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
Nous allons donc l'appliquer dans notre fonction de retrait de la classe compte comme suit :
/* Le montant à retirer doit toujours être > au solde actuel */
public void retrait(int montant) {
if (montant > solde) {
throw new MontantSoldeDoitEtreSuperieurAuMontantRetraitException (
"Le solde actuel de " + compte.getSolde( ) + " euros est inférieur par rapport au montant de " + montant + " euros que vous souhaitez retirer");
}
this.solde -= montant;
soldeActuel();
}
En effet, nous levons notre exception à l'aide du mot-clé throw. Ainsi à l'aide de ce code, nous générerons une exception permettant au programme de gérer les retraits supérieurs au solde courant.
Ensuite on spécifie l'exception ainsi levée partout où la méthode (la méthode retrait( )
) qui la lève est appelée.
public void retrait(int montant) throws MontantSoldeDoitEtreSuperieurAuMontantRetraitException { ... }
public static void main(String[] args) throws InterruptedException, MontantSoldeDoitEtreSuperieurAuMontantRetraitException { ... }
C:\>javac Compte.java
Bonjour et Bienvenue dans notre banque
Tapez 1 ==> Vérifiez le solde de votre compte
Tapez 2 ==> Faire un dépôt
Tapez 3 ==> Faire un retrait
Tapez 4 pour enregistrer les opérations effectuées et quitter l'application
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
3
Entrez le montant du retrait
400
Exception in thread "main" exceptions.MontantSoldeDoitEtreSuperieurAuMontantRetraitException
at exceptions.Compte.retrait(Compte.java:50)
at exceptions.Compte.main(Compte.java:28)
Process finished with exit code 1
On voit maintenant que lorsqu'un utilisateur tente de retirer 400 euros alors que son solde est de 100 euros, le compilateur Java affiche notre exception qui défend cette opération.
Nous allons maintenant gérer notre exception à l'aide du mécanisme de capture et de gestion des exception des exceptions en Java, le try-catch-finally.
Indice
3. Capture et gestion des exceptions
Ce code utilise la ressource scanner sans pour autant la libérer à la fin de nos opérations.
Ensuite on peut directement capter et afficher le message de l'exception personnalisée écrite ci-dessus dans la
main( )
de l'application.
Procédons d'abord par la capture de notre exception personnalisée de type MontantSoldeDoitEtreSuperieurAuMontantRetraitException et libérer la ressource scanner qu'on utilise.
...
Scanner sc = new Scanner(System.in);
try {
...
} catch (MontantSoldeDoitEtreSuperieurAuMontantRetraitException exception) {
System.out.println(exception.getMessage());
} finally {
sc.close();
}
}
On remarque ici qu'on a enlevé la spécification de l'exception MontantSoldeDoitEtreSuperieurAuMontantRetraitException dans la déclaration de la méthode main( )
puisque maintenant on a capté et géré l'exception en question à l'aide du mécanisme du try-catch-finally.
On a aussi libéré la ressource du scanner dans le bloc de code finally.
Indice
Pour finir, nous allons remplacer le mécanisme du try...catch...finally par celui du try-with-resources pour rendre le code plus succinct.
try (Scanner sc = new Scanner(System.in)) { ... }
Solution
Le résultat final
Voici donc notre programme ainsi rendu robuste et comprenant les bonnes règles de gestion des exceptions.
import java.util.Scanner;
public class Compte {
private int solde = 100;
public static void main(String[] args) throws InterruptedException {
Compte compte = new Compte();
System.out.println("""
Bonjour et Bienvenue dans notre banque
\tTapez 1 ==> Vérifiez le solde de votre compte
\tTapez 2 ==> Faire un dépôt
\tTapez 3 ==> Faire un retrait
\tTapez 4 pour enregistrer les opérations effectuées et quitter l'application """);
try (Scanner sc = new Scanner(System.in)) {
boolean isWrongAnswer = true;
while (isWrongAnswer) {
System.out.println("*********************************************************************************");
System.out.println("\tVeuillez saisir le numéro de la transaction que vous souhaitez effectuer:");
switch (sc.nextInt()) {
case 1 -> compte.soldeActuel();
case 2 -> {
System.out.println("Entrez le montant du dépôt");
compte.depot(sc.nextInt());
}
case 3 -> {
System.out.println("Entrez le montant du retrait");
compte.retrait(sc.nextInt());
}
case 4 -> {
System.out.println("Opération(s) enregistrée(s)! Au revoir");
Thread.sleep(2000);
isWrongAnswer = false;
}
default -> System.out.println("Tapez uniquement les nombres entre 1 et 4");
}
}
} catch (MontantSoldeDoitEtreSuperieurAuMontantRetraitException exception) {
System.out.println(exception.getMessage());
}
}
/* Le solde doit toujours être positif */
public int getSolde() {
return solde;
}
/* Le montant à retirer doit toujours être > le solde actuel */
public void retrait(int montant) throws MontantSoldeDoitEtreSuperieurAuMontantRetraitException {
if (montant > solde) {
throw new MontantSoldeDoitEtreSuperieurAuMontantRetraitException (
"Le solde actuel de " + this.getSolde() + " euros est inférieur par rapport au montant de " +
montant + " euros que vous souhaitez retirer");
}
this.solde -= montant;
soldeActuel();
}
public void depot(int montant) {
this.solde += montant;
soldeActuel();
}
public void soldeActuel() {
System.out.println("Le solde du compte courant est de " + this.getSolde() + " euros");
}
}
class MontantSoldeDoitEtreSuperieurAuMontantRetraitException extends Exception {
private final String message;
public MontantSoldeDoitEtreSuperieurAuMontantRetraitException(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
C:\>javac Compte.java
Bonjour et Bienvenue dans notre banque
Tapez 1 ==> Vérifiez le solde de votre compte
Tapez 2 ==> Faire un dépôt
Tapez 3 ==> Faire un retrait
Tapez 4 pour enregistrer les opérations effectuées et quitter l'application
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
1
Le solde du compte courant est de 100 euros
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
2
Entrez le montant du dépôt
150
Le solde du compte courant est de 250 euros
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
3
Entrez le montant du retrait
200
Le solde du compte courant est de 50 euros
*********************************************************************************
Veuillez saisir le numéro de la transaction que vous souhaitez effectuer:
3
Entrez le montant du retrait
100
Le solde actuel de 50 euros est moindre par rapport au montant de 100 euros que vous voulez retirer
Process finished with exit code 0