IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API standards et tierces Java Discussion :

[Détente] Les API étranges: ces classes au comportement curieux.


Sujet :

API standards et tierces Java

  1. #1
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    607
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 607
    Points : 671
    Points
    671
    Par défaut [Détente] Les API étranges: ces classes au comportement curieux.
    Tout le monde s'accorde à trouver le langage Java d'une qualité exceptionnelle. Aujourd'hui, il dépasse les 3500 classes, et pour l'humain moyen des limites sont franchies. Il y a peu de chances que quiconque dépasse jamais la maîtrise de mille classes. Et pour ma part, 500 sera certainement mon maximum.

    Pourtant, il me semble que toutes les classes ne se valent pas. Que certaines n'ont pas toujours été bien inspirées. Dites-moi si vous le croyez aussi, et si vous avez quelques exemples à titre d'illustration, mais pour ma part, je voudrais commencer par vous présenter la classe que je trouve d'entre toutes la plus baroque. Celle dont le comportement me semble le plus étrange et criticable: java.util.Calendar (et sa classe d'implémentation java.util.GregorianCalendar).

    GregorianCalendar est muni d'un constructeur étrange, qui accepte n'importe quoi, dont un mois basé sur un index 0. Cela fait que
    new GregorianCalendar(2007,11,25), c'est noël. Seulement, ce n'est pas intuitif. Notons que les jours, eux, sont basés sur l'index 1: 25 c'est 25.

    Le 48/16/2007 (new GregorianCalendar(2007, 15, 48)) c'est une date valide qui passe comme une lettre à la poste. Il s'agit du 18/4/2008.
    Donc, si votre programme commet des erreurs et génère des dates invalides, il trouvera avec GregorianCalendar un relais de choix pour le transport de données fausses. L'absence de garde-fou est très étonnante, dans le constructeur et les setters en tout cas.

    La soustraction de dates ne conduit pas à une durée. Cela produit des choses étonnantes. Justifiées, mais inattendues par bien des développeurs qui manipulent cette classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    import java.text.*;
    import java.util.*;
     
    public class Essai
    {
       public static void main(String[] args)
       {
          Calendar dt1 = GregorianCalendar.getInstance();
          Calendar dt2 = (Calendar)dt1.clone();
     
          int[] vComposants = {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND};
          String [] vszNoms = {"Année: ", "Mois: ", "Jour: ", "Heure: ", "Minutes: ", "Secondes: ", "Milisecondes: "};
     
          for (int iIndex = 0; iIndex < vComposants.length; iIndex ++)
             soustraire(dt1, dt2, vComposants[iIndex], vszNoms[iIndex]);
     
          Calendar dt3 = new GregorianCalendar(2007, 15, 48);
     
          String szFormat2 = "Le 48/16/2007 est une date valide: {0}/{1}/{2}.";
          Object[] args2 = {String.valueOf(dt3.get(Calendar.DAY_OF_MONTH)), String.valueOf(dt3.get(Calendar.MONTH)), String.valueOf(dt3.get(Calendar.YEAR))};
          System.out.println(MessageFormat.format(szFormat2, args2));
     
          System.exit(0);
       }
     
       /**
        * Soustraire une composante d'une date à une autre.
        * @param dt1 Date 1.
        * @param dt2 Date 2.
        * @param nComposant Composante.
        */
       static private void soustraire(Calendar dt1, Calendar dt2, int nComposant, String szNom)
       {
          int nAvant = dt2.get(nComposant);
          dt2.add(nComposant, -dt1.get(nComposant));
     
          String szFormat = "{3}{0} - {1} = {2}";
          Object[] args = {String.valueOf(nAvant), String.valueOf(dt1.get(nComposant)), String.valueOf(dt2.get(nComposant)), szNom};
          String szMessage = MessageFormat.format(szFormat, args);
     
          System.out.println(szMessage);
       }
    }
    Produit:

    Année: 2007 - 2007 = 1
    Mois: 10 - 10 = 0
    Jour: 13 - 13 = 31
    Heure: 14 - 14 = 0
    Minutes: 47 - 47 = 0
    Secondes: 46 - 46 = 0
    Milisecondes: 33 - 33 = 0

    Le 48/16/2007 est une date valide: 18/4/2008.


    Si le 31 pour le jour se justifie, le 1 pour la différence en années est plus difficile à comprendre.

    Certainement, le développeur se doit d'être vigilant, de manière générale. Mais cette API me semble une des plus délicate à interpréter et à manipuler.

  2. #2
    Membre expérimenté
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Points : 1 640
    Points
    1 640
    Par défaut
    Chez moi, le 25/11/2007, c'est le 25/11/2007 (test à l'appui)... Je suis d'accord pour dire que ce n'est pas évident à utiliser, mais quand on passe une date correcte, on a un résultat correct.
    Après, tout est question de jugeotte : 32/1/2008 correspond au 32è jour après le début du mois 1 de l'année 2008, soit le 1/2/2008. On peut éviter ce comportement en utilisant la méthode "setLenient" de la classe Calendar.

  3. #3
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    C'est un des désavantages de l'intégration en standard des librairies : un mauvais choix ne peut pas toujours être corrigé et se traine comme un boulet...



    Ici la classe Calendar est basé sur des constantes pour les mois et comme dans bien des domaines en informatique le premier index est 0 (Calendar.JANUARY == 0). On est d'accord qu'il s'agit là d'une grosse erreur de conception car cela prête à confusion

    Le problème étant que ce comportement ne peut plus être modifié sous peine de casser la compatibilité avec les programmes existants...




    Concernant l'absence de garde fou par contre c'est en fait assez pratique puisque cela permet de manipuler des dates plus simplement : par exemple ajouter 90 jours à une date sans se soucier que le résultat ne soit pas correcte ou avoir à découper cela en mois, ce qui peut s'avérer fastidieux...

    Un exemple, pour obtenir la date correspond à 90 jours après le 1 janvier 2007 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Calendar cal = new GregorianCalendar(2007, Calendar.JANUARY, 1 + 90);
    on n'a pas à se soucier de la longueur des mois, surtout que cela donnera un résultat différents les années bissextiles...

    Et ce comportement peut être interdit via setLenient(false) comme le signale Patriarch24





    Mais globalement je suis plutôt d'accord avec toi les Calendar de Java sont assez limité et peu évidente à prendre en main ! De plus il ne faut les prendre que pour ce qu'ils sont : des calendriers et rien de plus !





    L'API de date de Java est en fait assez limité puisqu'elle ne comporte que la notion de date, mais rien concernant l'heure (sans date), les durée ou encore les intervalles...

    Et le fait de ne pas pouvoir distinguer cela (et le comprendre) apporte une ambigüité qui fait qu'on prend des choses pour ce qu'elle ne sont pas (comme tu le dis, une soustractions de dates donne une date, ce qui n'est pas très logique).


    Actuellement, si on a besoin d'autre chose qu'un calendrier, la meilleure solution serait de se tourner vers Joda Time, une librairie complète pour la gestion des dates/heures et tout se qui s'en rapproche...

    A noter que cette API sert de base pour la JSR 310 qui intègrera toutes ces notions dans une nouvelle librairie standard (prévu pour Java 7).


    a++

Discussions similaires

  1. Réponses: 5
    Dernier message: 21/05/2008, 08h38
  2. Interfaçage avec les API de cdrtools
    Par jeanbi dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 17/07/2004, 16h35
  3. [VB6]Enumérer les attributs et les méthodes d'une classe
    Par HPJ dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 04/05/2004, 18h34
  4. faire un selection dans une image aves les APIs
    Par merahyazid dans le forum C++Builder
    Réponses: 3
    Dernier message: 30/04/2002, 10h44
  5. Une petite aide pour les API ?
    Par Yop dans le forum Windows
    Réponses: 2
    Dernier message: 04/04/2002, 21h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo