Correction TP1 JAVA – Exercice 2
Correction de l’exercice 2 du TP : Énoncé du TP1
Toutes le code ci-dessous est implémenté dans le fichier Times.java
, et dans la classe Times
.
2.1 Constructeurs
- Pour les secondes, on va mettre 0.
public Times(int hours, int mins) { this(hours, mins, 0); }
L’avantage d’utiliser l’autre constructeur, comme c’était déjà fait pour le constructeur de copie, est qu’on n’a pas à réécrire le code (évidemment dans cet exemple c’est très court, mais des constructeurs de classes plus complexes peuvent être très longs). De plus si on doit modifier, en cours de développement certains des arguments, on aura pas à reporter les mêmes modifications plusieurs fois, au risque d’en oublier. En règle générale il faut au maximum utiliser le même code pour les mêmes tâches.
- Dans le cas du constructeur sans argument, il faudrait écrire
public Times() { java.time.LocalDateTime now = java.time.LocalDateTime.now(); this(now.getHour(), now.getMinute(), now.getSecond()); }
Or ce n’est pas possible car l’appel à un autre constructeur doit être la première instruction. La compilation donne :
tp1$ javac Times.java Times.java:18: error: call to this must be first statement in constructor this(now.getHour(), now.getMinute(), now.getSecond()); ^ 1 error
Il faut toujours lire soigneusement les messages d’erreur si on veut avoir une chance de corriger.
On peut contourner ce problème en créant une fonction (qu’on appellera par exemple
initTimes
, qui sera appelée par les constructeurs.public void initTimes(int hours, int mins, int secs) { this.hours = hours; this.mins = mins; this.secs = secs; } public Times() { java.time.LocalDateTime now = java.time.LocalDateTime.now(); initTimes(now.getHour(), now.getMinute(), now.getSecond()); } public Times(int hours, int mins, int secs) { initTimes(hours, mins, secs); } public Times(int hours, int mins) { initTimes(hours, mins, 0); } public Times(Times source) { initTimes(source.hours, source.mins, source.secs); }
2.2 Méthodes
- On va commencer par créer plusieurs objets de type
Times
en utilisant les différents constructeurs, puis on les affichera et on appellera les différentes méthodes à tester, en affichant à la fois les objets qui auront été modifiés. -
public static void main(String[] args) { Times now=new Times(); System.out.println("it is "+now); Times other=new Times(now); System.out.println("other : "+ other); if (now.equals(other)) System.out.println("les 2 objets contiennent la même chose"); else System.out.println("les 2 objets contiennent des valeurs différentes"); other.addMinutes(1); System.out.println("valeur de now: "+now); System.out.println("valeur de other: "+other); if (now.equals(other)) System.out.println("les 2 objets contiennent la même chose"); else System.out.println("les 2 objets contiennent des valeurs différentes"); }
Exécution
tp1$ java Times it is 11:54:26 other : 11:54:26 les 2 objets contiennent la même chose valeur de now: 11:54:26 valeur de other: 11:55:26 les 2 objets contiennent des valeurs différentes
- Test de
addMinutes
public static void main(String[] args) { // ... other.addMinutes(90); System.out.println("other +90 min : "+ other); // ...
Exécution
tp1$ java Times it is 12:1:58 other : 12:1:58 other +90 min : 12:91:58
On a pas pris en compte le fait que le nombre de minute ne peut dépasser 59 !
- Un autre problème, que l’on peut aussi voir sur l’exécution précédente, est que l’affichage des minutes (et des secondes) est mauvais dans le cas de nombres inférieurs à 10.
- Correction de ces 2 méthodes
public void addMinutes(int n) { this.mins+=n; if (this.mins>=60) { this.hours+=(this.mins/60); this.mins=this.mins%60; } } @Override public String toString() { String offsetM=mins<10?"0":""; String offsetS=secs<10?"0":""; return hours+":"+offsetM+mins+":"+offsetS+secs; }
Exécution
tp1$ java Times it is 12:02:00 other : 12:02:00 other +90 min : 13:32:00
- Cette ligne est parfaitement correcte pour JAVA. Cela va créer une heure qui,
elle, n’aura aucun sens. - Pour éviter cela il faut faire des vérifications au moment de la création d’une heure. Il y a plusieurs stratégies.
- La première consiste à tenter de corriger le problème (mais ce n’est pas toujours possible) – par exemple ici on pourrait calculer que 99 secondes, c’est 1 min 39, et ajouter cette minute au nombre de minutes, puis voir que 66 minutes c’est 1h et 6 minutes pour aboutir à 2:06:39. Si on dépasse 24h là on aura un problème (qu’on ne peut pas vraiment résoudre dans ajouter la date – c’est pourquoi toutes les classes permettant de manipuler des heures sont en fait des classes Date-Heure, par exemple la classe que nous avons utilisé pour le constructeur sans argument
LocalDateTime
. - La seconde consiste à envoyer un message d’erreur, et arrêter le programme.
- Enfin les langages modernes (dont Java) proposent un mécanisme appelé « Gestion d’exceptions », qui permet de récupérer ce type d’erreur sans arrêter le programme (mais nous le verrons plus tard).
- La première consiste à tenter de corriger le problème (mais ce n’est pas toujours possible) – par exemple ici on pourrait calculer que 99 secondes, c’est 1 min 39, et ajouter cette minute au nombre de minutes, puis voir que 66 minutes c’est 1h et 6 minutes pour aboutir à 2:06:39. Si on dépasse 24h là on aura un problème (qu’on ne peut pas vraiment résoudre dans ajouter la date – c’est pourquoi toutes les classes permettant de manipuler des heures sont en fait des classes Date-Heure, par exemple la classe que nous avons utilisé pour le constructeur sans argument
2.3 De nouvelles méthodes
-
public boolean isBefore(Times other) { return (this.hours<other.hours) || (this.mins < other.mins) || (this.secs < other.secs); } public boolean isAfter(Times other) { return !isBefore(other)&&!equals(other); }
-
public void addSecondes(int n) { this.secs+=n; if (this.secs>=60) { this.addMinutes(this.secs/60); this.secs=this.secs%60; } }
-
- Calculer la durée entre 2 heures.
- Afficher à différents formats (3.12am, ou 12h 8′ et 14 »)
- Gestion des fuseaux horaires (mais cela n’a de sens que si la date est incluse.
2.4 Une alarme
-
public void minuteur(int nbSecs) { Times alarm=new Times(this); alarm.addSecondes(nbSecs); while (!alarm.equals(new Times())) { //sleep(500); } System.out.println("Done! "+(new Times())); }
- Attention cela va bloquer le système en attendant l’exécution. Il faudrait mettre le processus en attente (
sleep
), nous verrons cela plus tard avec la notion deThread
.