Cours BUT Info

TP 4 — Manipulation des exceptions

Diagnostics de six fragments fautifs, division blindée jusqu'au calcul réussi, conteneurs à transvaser automatiquement — et le complément « presque-biathlon » avec trois exceptions personnalisées.

Objectif du TP : lire un fragment de code et prédire s'il compile — et sinon pourquoi —, blinder une saisie jusqu'au calcul réussi, et concevoir des exceptions personnalisées dont le traitement porte la logique métier. Le supplément synthétise le tout avec collections, enums et héritage.

1. Six fragments à diagnostiquer

Pour chaque fragment : compile-t-il, quelle erreur, comment corriger ? Verdicts :

  1. example1 appelle doIt() déclarée throws Exception sans try/catch ni propagation : une checked ni traitée ni déclarée — ça ne compile pas. Correction : try/catch, ou throws à son tour ;
  2. example2 fait throw new MyException(); sans clause throws : MyException dérive d'Exception, donc checked — à déclarer dans la signature ;
  3. example3 attrape Exception pour une MyException : ça compile — mais le catch générique intercepte aussi toutes les autres exceptions. Bonne pratique : le type le plus précis possible ;
  4. example4 retourne data, affectée seulement dans le try : si getData() lève, la variable n'est jamais initialisée — erreur de compilation au return. Au passage, déclarer throws NullPointerException ne sert à rien (unchecked). Correction : initialiser data ;
  5. example5 appelle doItFinally() qui lève une RuntimeException : ça compile — une unchecked n'a rien à déclarer ni attraper. doItFinally est un faux ami : aucun bloc finally n'intervient ;
  6. le main place catch (RuntimeException e) avant les catch de ArrayIndexOutOfBoundsException et ArithmeticException : ces deux types en dérivent, leurs blocs sont inatteignables — ça ne compile pas. Correction : réordonner du spécifique au générique.

2. La division blindée

Fournis : un tableau tab, une méthode division(index, divisor) qui renvoie tab[index]/divisor, et statement() qui saisit les deux entiers via LocalKeyboard.readInt. Trois dangers se cumulent : KeyboardException (paquetage tpQU.tp04, levée quand autre chose qu'un entier est lu), ArrayIndexOutOfBoundsException (index hors tableau), ArithmeticException (diviseur zéro). Consigne : gérer les erreurs « jusqu'à ce qu'un calcul soit effectivement mené à bout » — donc boucler :

public static void statement() {
    boolean done = false;
    while (!done) {
        try {
            int x = LocalKeyboard.readInt("Write the index of the integer to divide: ");
            int y = LocalKeyboard.readInt("Write the divisor: ");
            System.out.println("The result is: " + division(x, y));
            done = true;                       // seulement si tout a réussi
        } catch (KeyboardException | ArrayIndexOutOfBoundsException | ArithmeticException e) {
            System.out.println("Réessayez.");
        }
    }
}

Point clé : done = true après la division, jamais avant — sinon une saisie ratée terminerait la boucle.

3. Conteneurs à transvaser

Des conteneurs de capacités différentes : BLISTER (1 chose), BOX (10), CRATE (50). On peut ajouter une quantité à condition de ne pas excéder la capacité ; sinon une exception est levée, et deux solutions : transvaser dans un conteneur plus grand, ou l'ajout échoue.

Q1 et Q2 — le socle. L'enum Container porte la capacité (capacity, constructeur privé, getCapacity()) ; la classe Thing (name, quantity, container) fixe sa quantité à 0 si la quantité initiale est incompatible avec le conteneur fourni.

Q3 à Q5 — l'architecture des exceptions, qui est le vrai sujet :

  • ExtendedException : classe vide, qui se contente d'hériter d'Exception ;
  • setQuantity(int) privée : lève ExtendedException si l'ajout excède la capacité ;
  • transferToLargerContainer() : transvase vers un conteneur plus grand ;
  • add(int quantity) : ajoute la quantité ou lève ExtendedException ; son traitement mène au transvasement vers un conteneur plus grand — s'il en existe — puis l'ajout est effectué.

Le scénario fourni dit tout :

Thing [name=uneThing, quantity=3, container=BOX]
Thing [name=uneThing, quantity=23, container=CRATE]
Thing [name=maThing, quantity=0, container=BOX]
Impossible addition !
Thing [name=maThing, quantity=0, container=CRATE]

Lecture : uneThing (3 dans une BOX) reçoit add(20) — 23 dépasse la boîte, l'exception est traitée par transvasement vers CRATE et l'ajout aboutit. maThing démarre à 12 dans une BOX : incompatible, quantité ramenée à 0. Son add(60) échoue même en CRATE (60 > 50) : « Impossible addition ! » — le transvasement a bien eu lieu, sans rollback. Q6 — commit : « tpQU-04::exo-boite », puis poussez.

4. Supplément : la course de presque-biathlon

Synthèse exceptions + collections + enum + héritage. La course peut être individuelle, par équipe ou par pays ; elle enchaîne des étapes de ski (temps de parcours) et de tir (tirs ratés convertis en pénalité temporelle propre à chaque étape). Le score le plus faible est le meilleur. Soyez rigoureux sur les signatures : les tests fournis en dépendent.

  • Competitor : identifiant automatique dès 0, nom, nationalité (Country), équipe (Team). Les enums Country — FRANCE(FR), GERMANY(GE), RUSSIA(RS), SWEDEN(SE), AUSTRIA(AT), ITALY(IT) — et Team (TEAM_1 à TEAM_3) s'affichent en version courte. toString sous la forme <ID>-<NAME>(<COUNTRY>) -> <TEAM>, isFrom(...) (pays ou équipe), equals sur identifiant et nom. resetCpt() remet le compteur à zéro : les tests recréent des instances entre chaque test. Validez avec CompetitorTest ;
  • Stage : identifiant automatique commun à toutes les étapes. SkiingStage porte une distance, ShootingStage un nombre de tirs à réussir et une pénalité par tir raté (10 par défaut) ; affichages attendus : 0(Skiing)1000m et 1(Shooting)5shots/penaltyPerMiss=10s. Les résultats vivent dans une table associative Competitor → entier ; trois exceptions personnalisées — Exception_UnknownCompetitor (non inscrit à la course), Exception_NoResult (aucun score), Exception_InvalidRecord (déjà enregistré) — servent clear(), getNbRecord(), record(...) et getScore(...) (surcharge sur une liste, scores additionnés). Validez avec StageTest ;
  • Race : un nom, un Set<Stage>, une table associative concurrent → numéro (le juge relève le numéro qui passe). Compteurs et indicateurs (getNbCompetitors, getNbTeams, getNbCountries, getTotalNbShots, getTotalLength), clearResults() déléguée, isValid(...) (lève et propage Exception_UnknownCompetitor), record(...) et getScore(...) qui propagent les exceptions, getCompetitorScore (somme), getTeamScore/getCountryScore (moyennes en double), classements du meilleur au moins bon (competitorRanking, teamRanking, countryRanking), et deserterSet() — les concurrents sans résultat. Validez avec RaceTest.

Commit final : « tpQU-04::exo-biathlon », puis poussez l'ensemble.


tpQU_04.pdf

R2.03 · TP 4 — Manipulation des exceptions · 3 pages

Consultation seule — téléchargement désactivé

Chargement du document…

tpQU_04_sup.pdf

R2.03 · TP 4 supplément — Course de presque-biathlon · 4 pages

Consultation seule — téléchargement désactivé

Chargement du document…

Dernière mise à jour le

Sur cette page