programmation Java (école d'ingénieur) · Chapitre 8 · Exercice de TD
Une date toujours valide
Encapsulation, membres de classe et paquets · niveau 3 (difficile)
Énoncé
Écrire une classe immuable Date (jour, mois, année) dont l'invariant est « la date existe dans le calendrier grégorien ». Une année est bissextile si elle est divisible par 4 mais pas par 100, ou divisible par
- Écrire :
- les méthodes
staticestBissextile(int a)etjoursDansMois(int m, int a); - le constructeur, qui refuse toute date invalide ;
- une méthode
lendemain(); toString()au formatjj/mm/aaaa.
Tester les lendemains du 28/02/2024, du 28/02/2026 et du 31/12/2026, et la validité du 29/02/1900, du 29/02/2000 et du 31/04/2026.
Corrigé
Le constructeur vérifie l'invariant avec joursDansMois ; lendemain distingue trois cas (même mois, mois suivant, année suivante), et chaque nouvelle date repasse par le constructeur.
// Une date toujours valide, immuable.
final class Date {
private final int jour, mois, annee;
Date(int jour, int mois, int annee) {
if (mois < 1 || mois > 12 || jour < 1 || jour > joursDansMois(mois, annee)) {
throw new IllegalArgumentException("date invalide : " + jour + "/" + mois + "/" + annee);
}
this.jour = jour;
this.mois = mois;
this.annee = annee;
}
static boolean estBissextile(int a) {
return (a % 4 == 0 && a % 100 != 0) || a % 400 == 0;
}
static int joursDansMois(int m, int a) {
switch (m) {
case 2: return estBissextile(a) ? 29 : 28;
case 4: case 6: case 9: case 11: return 30;
default: return 31;
}
}
Date lendemain() {
if (jour < joursDansMois(mois, annee)) return new Date(jour + 1, mois, annee);
if (mois < 12) return new Date(1, mois + 1, annee);
return new Date(1, 1, annee + 1);
}
@Override
public String toString() { return String.format("%02d/%02d/%d", jour, mois, annee); }
}
public class Ex11Date {
public static void main(String[] args) {
System.out.println(new Date(28, 2, 2024).lendemain());
System.out.println(new Date(28, 2, 2026).lendemain());
System.out.println(new Date(31, 12, 2026).lendemain());
for (int[] d : new int[][] {{29, 2, 1900}, {29, 2, 2000}, {31, 4, 2026}}) {
try {
System.out.println(new Date(d[0], d[1], d[2]) + " valide");
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}
}
29/02/2024
01/03/2026
01/01/2027
date invalide : 29/2/1900
29/02/2000 valide
date invalide : 31/4/2026
1900 est divisible par 100 sans l'être par 400 : elle n'est pas bissextile. 2000, divisible par 400, l'est. Dans le constructeur, l'ordre des tests compte : on vérifie que le mois est dans avant d'appeler joursDansMois. Ici, l'appel avec un mois invalide retournerait 31 sans dommage, mais dans une version qui lirait un tableau indexé par le mois, il provoquerait un débordement d'indice. La bibliothèque de Java fournit une classe java.time.LocalDate qui fait tout cela, et bien plus.
100 % gratuit
La suite du chapitre est sur Adloun
- 10 autres exercices corrigés dans ce chapitre
- Les 2 QCM du chapitre, le premier sans compte
- Le podcast et la vidéo du chapitre : 2 minutes d'écoute sans compte
- Le tuteur, qui guide pas à pas sans donner la réponse
Sans compte : le cours, le premier QCM et 2 minutes de podcast et de vidéo. Exercices et tuteur : inscription gratuite en 30 secondes, sans carte bancaire.