Journal Le point sur Java 7

Posté par (page perso) .
Tags : aucun
14
16
avr.
2010
Pour les développeurs Java, les nouveautés que réserve SUN pour les prochaines versions de son langage Orienté Objet sont autant de sujets d'attentes, de débats, et même pour certains ... d'espoirs ! Beaucoup a été dit et surtout bloggué depuis le lancement du projet Java 7 "Dolphin", les échanges ont été nombreux et le débat fourni. À l'heure où la sortie de cette dernière mouture de Java est imminente, faisons le point sur le sujet et tout particulièrement sur le projet Coin de SUN et des améliorations qu'il apporte à Java 7.

Plusieurs chantiers majeurs d'évolutions ont donc été lancés en interne autour d'OpenJDK. Mais SUN a aussi voulu intégrer la communauté Java dans le projet pour prendre en compte le retour d'expérience des utilisateurs quotidiens de sa plate-forme. À cet effet, SUN a initié le projet Coin dans le but de lister les "petites" améliorations qui pourraient être intégrées. SUN a donc misé sur le débat ouvert puisqu'il était permis à tous de soumettre ses idées d'évolution. Et le moins que l'on puisse dire est que ce "projet autour du projet" a porté ses fruits puisque ce n'est pas moins de 70 propositions qui ont été soumises (voir cet article du blog d'Alex Miller qui en a fait une liste exhaustive et documentée). S'en est suivie une longue période de débats, mais après quelques rebondissements de dernière minutes, nous connaissons (enfin) les 5 propositions de la communauté qui ont été retenues :

* Possibilité d'utiliser des String dans les switch
Tout développeur Java s'est déjà retrouvé dans l'impossibilité d'utiliser des chaînes de caractères dans les structures switch. Cette fonctionnalité bien pratique existait depuis longtemps dans bien des langages et ce sera bientôt chose faite pour Java.

* Gestion automatique des ressources
La mémoire est gérée automatiquement en Java et cela dans le but de soulager le développeur dans le développement d'applications haut niveau. Cependant cela n'était pas le cas des autres ressources comme les documents qu'il fallait ouvrir, et surtout, fermer à la main. Cette amélioration de Java 7 vise à automatiser cette gestion même s'il est peu probable que l'on en arrive au niveau de gestion de la mémoire.

* Amélioration des instanciations génériques
Voici une nouveauté qui ne sera en fait qu'une simplification d'écriture dans le but d'alléger le code. Il ne sera désormais plus nécessaire de spécifier le type des éléments de listes génériques lors de la déclaration ET de l'allocation, celle-ci devenant évidente.

Voici un exemple avec la syntaxe actuelle :
List liste = new ArrayList();

Java 7 permettra d'écrire :
List liste = new ArrayList<>();

* Simplification des varargs
Voici une autre modification qui a pour but de simplifier la vie du développeur sans pour autant apporter de grande nouveauté. En l'occurrence l'emploi du code suivant qui était jusqu'alors sujet au warning "uses unchecked or unsafe operations".
static  List asList(T... elements) { ... }
static List stringFactories() {
Callable a, b, c;
...
*// Warning: **"uses unchecked or unsafe operations"*
return asList(a, b, c);
}

* Support de langages de script
Un des sujets d'attentes était la possibilité d'intégrer des langages de script comme le Ruby et le Python dans la JVM. C'est désormais le cas via la JSR 292 (Java Specification Request). Ceci est expliqué plus en détail dans ce mail d'archive de la mailing list du projet Coin.

* Closures ou non?
Comme expliqué plus haut dans l'article, des évènements de dernières minutes sont venus créer des remous dans la communauté Java. Beaucoup de membres espéraient en effet que la proposition d'intégration des Closure allait être acceptée. Cependant celles-ci ne figuraient pas dans la liste des améliorations retenues par le projet Coin pour Java 7. Rebondissement lors de la conférence Devoxx 2009 : Mark Reinhold, ingénieur chez SUN sur le projet OpenJDK annonçait finalement leur acceptation. Depuis aucune information n'est venue confirmer ou infirmer ce dernier commentaire.
Pour mémoire, les closures, qui existent déjà dans nombre de langages comme le C++, sont des sous-fonctions définies dans le corps de fonctions et qui portent sur les variables locales de cette fonction.

Comme on peut le voir, les nouveautés apportées par le projet Coin pour Java 7 sont principalement d'ordre esthétique mais ce sont aussi ces détails qui facilitent le quotidien du développeur. À noter que nombre de propositions plus "de fond" n'ont pas été retenue comme par exemple l'autorisation des multi-catch pour gérer plusieurs types d'exceptions en une fois.

SUN développe aussi des efforts en direction des performances de la JVM comme en témoigne ce projet de compression des adresses des pointeurs 64 bits. Mais une amélioration plus intéressante encore se situe au niveau du Garbage Collector, l'outil de libération mémoire des objets du développeur. Le nouveau Garbage Collector "Garbage First G1" devrait passer moins de temps en pause et ainsi d'améliorer l'efficacité de la JVM. Espérons que ces promesses se réaliseront : le Garbage Collector joue un rôle sensible et est souvent un acteur majeur dans nombre de cas d'applications aux performances déteriorées. Dans la veine de ces améliorations, citons aussi le classloader et la concurrence dans les accès IO qui devraient être revus ainsi qu'une bonne partie du chapitre 2D des applications client léger Java.

Autre grande nouveauté du langage Java à proprement parler : la possibilité d'annoter les types afin de leur adjoindre certaines caractéristiques. L'auteur de la JSR en cause propose des exemples très parlants dont la seule vue devrait inspirer les développeurs Java tant ils produisent du code simple et clair :
public int size() @Readonly { ... }

Map<@NonNull String, @NonEmpty List> files;

Au sujet des tableaux :
Document[@Readonly] docs1;
Document[][@Readonly] docs2 = new Document[2][@Readonly 12];

Cast de type :
myString = (@NonNull String)myObject;

Tests de types :
boolean isNonNull = myString instanceof @NonNull String;

Création d'objet :
new @NonEmpty @Readonly List(myNonEmptyStringSet)

Clauses throws
void monitorTemperature() throws @Critical TemperatureException { ... }

Dernière amélioration majeure qui va sûrement retenir l'attention des utilisateurs de Java : la modularisation de la JVM. Le projet Jigsaw attendait depuis longtemps dans les cartons de SUN mais n'avait pas réussi à voir le jour tant ses implications sont importantes. La JVM de SUN est devenue très volumineuse et cela se ressent lors de son téléchargement et de son lancement. Ce projet a pour but de modulariser la JVM pour permettre de ne faire télécharger à l'utilisateur que ce dont il a besoin un peu à la manière d'un distribution Linux. En cas d'utilisation d'une nouvelle application, il suffirait alors de compléter la JVM par les modules qui n'ont pas encore été téléchargés la première fois et dont cette nouvelle application a besoin. L'apport en terme de souplesse de lancement est tout aussi prometteur.

Voilà donc de bien belles promesses qui ne demandent plus qu'à être testées dans les snapshots disponibles de Java 7.
  • # Closures

    Posté par . Évalué à 7.

    Pour mémoire, les closures, qui existent déjà dans nombre de langages comme le C++, sont des sous-fonctions définies dans le corps de fonctions et qui portent sur les variables locales de cette fonction.

    Dans la nouvelle norme C++0x c'est vrai, mais celle ci n'a pas encore été publié par l'ISO et je ne crois pas qu'un compilateur la supporte en entier.

    Par contre, GCC 4.5 qui vient de sortir, voir la dépèche de patrick_g[1], support les expressions lambda et donc les fermeture (closure en anglais) en C++.

    [1] Sortie de GCC 4.5 : http://linuxfr.org/2010/04/14/26729.html
    • [^] # Re: Closures

      Posté par . Évalué à 3.

      Si je ne me trompe pas boost permet d'en faire.

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

  • # \_o<

    Posté par (page perso) . Évalué à 4.

    PAN!
  • # Typo?

    Posté par (page perso) . Évalué à 2.

    List liste = new ArrayList(); -> ce serait pas plutôt new ArrayList ?
    • [^] # Re: Typo?

      Posté par (page perso) . Évalué à 4.

      Raaah, mauvaise manip:
      il fallait lire: "new ArrayList<List>()"
      • [^] # Re: Typo?

        Posté par (page perso) . Évalué à 5.

        Je vois mieux ou se situe la simplification car en lisant le journal je ne comprenais pas :p
      • [^] # Re: Typo?

        Posté par . Évalué à 1.

        J'aurai plûtot dit List<> = new ArrayList()
        ou List = new ArrayList<>()
        Si je me souviens bien d'un article vu sur dvp.com
  • # Liberté

    Posté par (page perso) . Évalué à 7.

    Java, ou plus précisément la bibliothèque Java standard de Sun, est-elle finalement entièrement libérée ?
    • [^] # Re: Liberté

      Posté par (page perso) . Évalué à 1.

      • [^] # Re: Liberté

        Posté par (page perso) . Évalué à 2.

        En fait non, les liens que tu proposes concernent l'implémentation GNU des libraries java, et non le code libéré par Sun.

        Le projet d'implémentation libre de java, provenant majoritairement de la libération de l'implémentation propriétaire, est OpenJDK.
        La page est: http://openjdk.java.net/projects/jdk6/

        Je n'ai pas trouvé de statut exact d'OpenJDK, mais c'est la version de Java proposée par défaut par ma distribution (ArchLinux) et elle marche très bien avec les quelques logiciels Java que j'ai eu l'occasion d'utiliser.

        Excusez l'absence d'accents dans mes commentaires, j'habite en Allemagne et n'ai pas de clavier francais sous la main.

    • [^] # Re: Liberté

      Posté par . Évalué à 2.

      À ma connaissance oui.

      Sun à libéré le JDK début 2007 (openjdk 7 puis openjdk 6 un peu plus tard). Certaines petites parties n'ont pas été libérée car le code n'appartient pas à Sun. Redhat s'est mis sur le coup en créant icedtea, un sous projet d'openjdk qui vise à fournir un version pour linux 100% open source (pour être packagable dans fedora, debian & co) et qui peut se builder avec des outils libres. Depuis juin 2008 Icedtea 6 (la version packagée par Fedora 9) est complétement open source et certains builds ont été validés par en passant le TCK. Ce sont donc officiellement des implémentations de Java.

      Reste que je ne sais pas si tout le code d'icedtea permettant d'avoir un openjdk entièrement libre, a été mergé dans openjdk 6 et openjdk 7. Depuis le temps c'est probable mais à vérifier.
  • # Simplification des varargs

    Posté par (page perso) . Évalué à 1.

    Templeet a dû bouffer une partie de ton code parce que tes exemples sont étrange.

    Pour un véritable exemple voir http://tech.puredanger.com/java7/#typeinference

    L'association LinuxFr ne saurait être tenue responsable des propos légalement repréhensibles ou faisant allusion à l'évêque de Rome, au chef de l'Église catholique romaine ou au chef temporel de l'État du Vatican et se trouvant dans ce commentaire

    • [^] # [ERRATUM] Amélioration des instanciations génériques

      Posté par (page perso) . Évalué à 1.

      Mauvais titre de mon post. Je voulais mettre "Amélioration des instanciations génériques"

      L'association LinuxFr ne saurait être tenue responsable des propos légalement repréhensibles ou faisant allusion à l'évêque de Rome, au chef de l'Église catholique romaine ou au chef temporel de l'État du Vatican et se trouvant dans ce commentaire

  • # Scala

    Posté par . Évalué à 5.

    Scala intégre déjà la plupart des fonctionnalités discutées pour Java7, à la différence que la version Scala est beaucoup plus puissante.
    Des String dans les switch? Pfff! Scala intègre déjà cette fonctionnalitée en version survitaminée (et non limitée aux String). Et ce langage offre énormément d'autres fonctionnalités simplifiant la vie du programmeur.

    Je suis conscient qu'il est important voir essentiel de faire évoluer le langage Java en lui-même. Mais pour le dev Java lambda, ça n'est peut-être pas une mauvaise idée d'envisager l'utilisation d'un langage comme Scala, qui reste compatible avec les libs Java, tout en offrant les mêmes perfs (pour généralement trois fois moins de code).

    http://www.scala-lang.org/node/25
    • [^] # Re: Scala

      Posté par . Évalué à 2.

      Zut tu m'as doublé :)
    • [^] # Re: Scala

      Posté par . Évalué à 2.

      Des switch/case aussi puissant que les when/given de perl ?Tu m'en diras tant...

      (On est plus vendredi mais c'est comme si)

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

      • [^] # Re: Scala

        Posté par . Évalué à 3.

        Bah la différence c'est que le pattern matching de Scala (et de caml d'ailleurs) de base s'appuie sur la notion de typage pour faire des trucs surs (genre vérifier que tu matches bien tout les cas possibles, ou que tu matches un truc matchable).

        Et ensuite les extractors de Scala permettent d'aller plus loin pour faire des trucs puissant :)

        T'façon perl c'est naze c'est du typage dynamique (et hop).
  • # Ridicule ?

    Posté par . Évalué à 4.

    Salut,

    Je vais mettre les pieds dans le plat, mais je trouve ces nouveautés complètement ridicules quand on voit ce qui se fait dans des langages comme Scala qui ne sont pas plus difficiles à utiliser que Java (parce que tournant sur la JVM et parce que facile à s'y mettre quand on vient de Java).

    Si on reprend ces nouveautés :
    1) Possibilité d'utiliser des String dans les switch :
    Le pattern matching est mille fois plus puissant, en particulier en Scala avec la notion d'extracteurs qui permet de définir comment matcher.
    Voir http://www.scala-lang.org/node/120

    2) gestion automatique des ressources :
    Ça peut se programmer sous forme de bibliothèque à partir du moment où on a des fonctions anonymes (ou des closures, pas sûr de saisir la différence...) et des fonctions d'ordre supérieur.
    Voir http://stackoverflow.com/questions/2207425/what-automatic-re(...)

    3) Amélioration des instanciations génériques :
    Alors là, l'inférence de type fait ça depuis longtemps (qui a étudié caml à la fac ?)
    Voir http://www.scala-lang.org/node/127

    4) Simplification des varargs :
    Ça j'ai pas bien compris le truc, c'est peut-être effectivement intéressant...

    5) Support de langages de script :
    J'avais cru comprendre que la JSR-292 était pour les langages à typage dynamique (voir http://jcp.org/en/jsr/detail?id=292 ).
    À noter que Scala peut être utilisé comme langage de script sans pour autant qu'il soit à typage dynamique. Voir http://www.artima.com/scalazine/articles/steps.html par exemple.

    En fait, pour dire un truc horrible, Scala c'est un peu tout ce qui nous plaisait dans Caml mais sur la JVM et mixé avec de l'objet à la Java (oui parce qu'il existe aussi les objets à prototypes qui n'ont rien à voir avec Java).
    En fait c'est beaucoup plus fort que ça, mais je ne rentrerais pas dans les détails de Scala et de la fusion objet/fonctionnel, des systèmes de typages avancées, des continuations, des DSL, des acteurs, des..., ... etc . ... ..

    Voilà pour la pub, l'objectif ici était de montrer que ces améliorations sont sympa mais c'est pas ça qui rendra vraiment Java meilleur, c'est des détails qui ne changeront pas grand chose je trouve...

    (À noter qu'il existe pleins d'autres langages intéressants qui auraient pu servir à faire ce commentaire, mais moi c'est Scala que j'aime :)
    • [^] # Re: Ridicule ?

      Posté par (page perso) . Évalué à 1.

      Finalement c'est que je disais il y a deux jours ;-)
      http://linuxfr.org/comments/1120526.html#1120526
    • [^] # Re: Ridicule ?

      Posté par . Évalué à 4.

      Scala a l'air génial, mais il ne faut pas oublier qu'il y a énormément de projets Java dont le code source pourra être amélioré avec ces petites évolutions sans avoir à tout réécrire.

      A ce propos, est-ce qu'il existe un outil pour transformer un code source Java en Scala?
      • [^] # Re: Ridicule ?

        Posté par (page perso) . Évalué à 2.

        L'intérêt de transformer du code source Java en code source Scala est assez limité (du code Scala écrit à la mode Java perd tout l'intérêt de Scala). À mon avis ça doit être possible et assez peu compliqué vu qu'il y a une correspondance (mais pas une bijection) entre les concepts Java et Scala. Ça pourrait être envisagé pour faciliter la migration de certains codes effectivement.

        Par contre des travaux sont en cours pour passer du code Scala en code Java afin de rassurer les décideurs qui voudraient choisir Scala tout en conservant une porte de sortie.

        http://www.sts.tu-harburg.de/people/mi.garcia/ScalaCompilerC(...)
        http://www.sts.tu-harburg.de/people/mi.garcia/ScalaCompilerC(...)
        • [^] # Re: Ridicule ?

          Posté par . Évalué à 2.

          Je travaille avec Java et Scala me fait envie. Si j'avais un moyen de convertir mes projets existants, ça m'inciterait à sauter le pas.
          • [^] # Re: Ridicule ?

            Posté par (page perso) . Évalué à 2.

            Tu peux d'ores et déjà mixer des projets écrits en Java et en Scala. En particulier, le plugin Maven le supporte [1] et le plugin Eclipse aussi (pour le reste je ne sais pas, mais ça ne veut pas dire que ça n'est pas supporté).

            Ça te permet d'avoir des classes écrites en Java ou en Scala dans un même projet et de migrer progressivement. Tu dois même pouvoir faire des choses un peu crade du type :
            Tu as une classe A pour laquelle tu veux réécrire la méthode toto en Scala.
            1) Tu renommes la classe A en A_Old (package private, tout ça) et tu la déclares abstraite
            2) Tu rends la méthode toto abstraite
            3) Tu crées une classe A en Scala qui hérite de A_Old et qui implémente la méthode toto.
            Je ne sais pas si c'est recommandable, mais bon ça doit être possible.

            [1] http://scala-tools.org/mvnsites/maven-scala-plugin/usage_jav(...)
      • [^] # Re: Ridicule ?

        Posté par (page perso) . Évalué à 2.

        Ya.

        http://www.javalinux.it/wordpress/java2scala/

        Et surtout : http://code.google.com/p/jatran/
        Qui a l'air assez fonctionnel. (J'ai failli partir dessus pour cracher du lisaac)

        « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

  • # Merci.

    Posté par . Évalué à 7.

    Alors après toutes ces critiques sur Java, je voudrais quand même dire merci à l'auteur du journal pour son travail, qui pourrait faire un début de dépêche pour le jour de la sortie de Java 7…
  • # .

    Posté par . Évalué à 2.

    J'aurai préféré 100 fois le "Enhanced null handling" [1] que le switch sur les chaines.

    Si j'étais courageux, je ferai quelques stats sur le code à ma disposition pour voir quelle est la fréquence d'apparition des 'switch' et la fréquence d'un 'if (a!=null) b = a.getC()'.


    [1] http://tech.puredanger.com/java7#null
    • [^] # Re: .

      Posté par . Évalué à 4.

      Faudrait plutôt faire des stats avec if(chaine=="a") then {}elsif(chaine=="b"){...} ce serait plus représentatif du besoin, je pense.

      Mais c'est vrai qu'un vrai pattern matching est quand même plus intéressant.
    • [^] # Re: .

      Posté par (page perso) . Évalué à 2.

      Et oui, null c'est mal :
      http://www.infoq.com/presentations/Null-References-The-Billi(...)

      D'où les types Maybe (en Haskell) ou Option (en Scala).
      En Scala :
      val a:Option[A] = uneFonctionQuiRenvoieUnAOuPas()

      À partir de là on peut soit :
      a match {
        case Some(x) => // c'est bien un A
        case None => //le cas "ou pas"
      }

      Ou alors :
      val s = a.getOrElse(valeurSiPasUnA)

      Voir aussi orElse, orNull, etc.
      • [^] # Re: .

        Posté par (page perso) . Évalué à 1.

        Bonjour,

        Je ne comprends pas l'avantage entre :

        a = getA();
        if (a == null) a = maisAllezDonneMoiUnA();

        et

        val a:Option[A] = uneFonctionQuiRenvoieUnAOuPas()
        val s = a.getOrElse(valeurSiPasUnA)
        ( ou l'autre méthode )

        Je ne cherche pas à te titiller hein, je veux vraiment comprendre n'ayant jamais fais de Scale/Haskell.
        Dans ton exemple je ne sais pas de quel type est le contenu de a (Option est un type à part entière qui m'empêche de taper dans le null?), alors qu'en Java je sais qu'il est ou null, ou du type voulu.
        Je n'arrive pas à voir l'avantage concrètement.

        Merci d'avance si tu peux m'éclairer :)
        • [^] # Re: .

          Posté par (page perso) . Évalué à 4.

          En fait le fait d'utiliser Option te force à prendre en compte le cas null/None.

          Vu autrement, quand tu as une variable de type A, tu es sûr que c'est bien un A et que tu peux appeler les méthodes de A sans craindre de NPE (Null-Pointer Exception).

          Dans la sémantique Java, tu ne peux jamais être sûr qu'une fonction qui renvoie un A ne te renvoie pas null à un moment. Le seul moyen de le savoir est de regarder dans la doc ou de tester à l'exécution.

          En Scala/Haskell, une fonction qui renvoie un A renvoie un A. Si jamais il se peut qu'elle ne puisse pas en renvoyer pour une raison quelconque, alors son type de retour est Option[A] et non A et les utilisateurs de la fonction doivent prendre en compte le cas None.

          Ça peut servir aussi quand tu veux chaîner des fonctions. Exemple en Java :
          a = getA()
          if (a == null) abort else {
            b = a.getB()
            if (b == null) abort else {
              c = b.getC()
          ...
          }

          L'équivalent si les get renvoyaient des Option serait :
          val v = getA().flatMap(_.getB()).flatMap(_.getC())
          v match {
            case Some(c) => ...
            case None => abort
          }

          ce qui peut s'écrire aussi:
          val v = for (a <- getA(), b <- a.getB(), c <- b.getC()) yield c
          v match {
            case Some(c) => ...
            case None => abort
          }
          • [^] # Re: .

            Posté par (page perso) . Évalué à 2.

            Ok je saisis mieux le principe, qui force en fait le développeur à gérer le cas d'un retour 'null'.
            Merci :)
        • [^] # Re: .

          Posté par (page perso) . Évalué à 4.

          Je ne sais pas en Scala, mais en Haskell, le type de la variable renvoyée est "Maybe a" (a étant un type, celui de celui que tu veux en retour) qui peut être "Nothing" ou "Just a", donc le type renvoyé par la fonction est cohérent. Ensuite tu peux passer ta variable à une autre fonction sans te soucier si tu as Nothing ou Just a en paramètre. Puis dans ta fonction du fais un filtrage de motif : Nothing -> valeurDeRetourSiRien ; Just x -> valeurDeRetourSi(x)
          • [^] # Re: .

            Posté par (page perso) . Évalué à 3.

            Bon, bah je réponds moins longuement et avec moins d'exemple que ci-dessus... et en plus plus tard. Tant pis.
      • [^] # Re: .

        Posté par . Évalué à 1.

        Sauf cas particulier, il est quand même facile de ne jamais renvoyer null, mais plutôt de balancer une exception. C'est plus une question d'habitude, mais avec des directives simples on peut éradiquer pas mal de NPE.
        Si en plus, on évite les initialisations de variable à null (ou à zéro, ou à ''), on garantit quand même à la compilation que le résultat renvoyé est géré, et on force les méthodes appelantes à gérer les cas d'erreur. C'est pas pour rien que le compilateur indique 'variable may not have been initialized': c'est pour que les cas non gérés aboutissent forcément à une levée d'exception.
        • [^] # Re: .

          Posté par . Évalué à 4.

          Sauf cas particulier, il est quand même facile de ne jamais renvoyer null, mais plutôt de balancer une exception.

          Et pour une fonctions getObjectById(int) ?
          Si elle ne trouve rien, elle ne doit pas lever d'exception, non ?
          • [^] # Re: .

            Posté par . Évalué à 3.

            Et pourquoi pas ? C'est ce que font certains ORM (Django notamment)
            • [^] # Re: .

              Posté par . Évalué à 8.

              Parce que les exceptions sont là pour indiquer des situations "exceptionnelles". Ne pas trouver un objet avec un ID donné est une situation normale, pas une exception.
              D'autant qu'il est beaucoup plus efficace de retourner un null et le tester au retour plutôt que de lancer des exceptions et de jouer du try{}catch(){}.

              Les exceptions ne sont pas faites pour gérer le fonctionnement normal du programme, si une exception est lancée ça indique qu'il y a un problème.

              (une petite recherche sur "exception flow control" donne plein de discussions sur le sujet)
              • [^] # Re: .

                Posté par . Évalué à 2.

                En l'occurence, la méthode getMachinById() se doit de renvoyer une MachinNotFoundException, simplement parce qu'un catch(MachinNotFoundException mnfe) {...} est mille fois plus explicite qu'un if(machin !null) {...} qui lui n'impose pas de else {log.error('oulalala');}.
                Renvoyer null ne donne aucune information sur le type d'erreur ayant mené à ce résultat, c'est donc insuffisant. Par exemple, on pourrait imaginer que l'id soumis est trop grand, vide, ou qu'il ne correspond à rien.
                Seule la méthode getMachinById() doit connaitre la nomenclature d'un Id, sinon chaque méthode appelante va dupliquer le code de validation d'un id.
                L'argument des performances pour la gestion des exceptions est fallacieux. Les exceptions ça va vite, et bien que ce soit verbeux, c'est lisible.
                Les exceptions ne sont pas là pour indiquer que le programme va partir en sucette à partir de maintenant. Elles sont là pour rendre plus clair le déroulement d'un programme.
                • [^] # Re: .

                  Posté par . Évalué à 5.

                  J'ai l'impression que tu cherches à traiter 2 comportements différents de cette méthode avec des exceptions, alors que l'un des 2 ne devrait pas !

                  Soit l'id est incorrect (null, string vide, n'a pas la bonne structure, ...), ce qui pourrait, en effet, être une source d'exception. Soit l'id est une valeur inconnue dans la base (par ex.), ce qui devrait renvoyer une valeur null...
                  • [^] # Re: .

                    Posté par . Évalué à 1.

                    Soit l'id est une valeur inconnue dans la base (par ex.), ce qui devrait renvoyer une valeur null...
                    Ou un autre résultat, par exemple en Scala :

                    getMachinById(id) match {
                       case None => /* do something because this machin does not exist */
                       case Some(machin) => */ do something with machin */
                    }


                    Je ne vois pas comment ça peut-être plu élégant et clair :)
                    • [^] # Re: .

                      Posté par (page perso) . Évalué à 3.

                      Oui d'autant plus qu'on n'est pas limité au type Option. Si on veut ajouter la cause de l'échec, on peut utiliser le type Either par exemple :

                      def getMachinById(id:ID): Either[Machin, String] = {
                        ...
                        if (machinUnavailable) Right("Machin non disponible")
                        else if (machinKaputt) Right("Machin cassé")
                        else Left(machin)
                      }

                      getMachinById(id) match {
                        case Left(a) => /* utiliser a (le machin renvoyé) */
                        case Right(msg) => println("Echoued with error: "+msg)
                      }

                      Enfin bref, tout sauf null !
                • [^] # Re: .

                  Posté par . Évalué à 2.

                  En l'occurence, la méthode getMachinById() se doit de renvoyer une MachinNotFoundException, simplement parce qu'un catch(MachinNotFoundException mnfe) {...} est mille fois plus explicite qu'un if(machin !null) {...} qui lui n'impose pas de else {log.error('oulalala');}.


                  Tu semble considérer que ne pas trouver ton machin est une erreur.
                  Moi ça me semble plutôt un comportement tout à fait normal, on cherche un certain machin, si on le trouve on en fera quelque chose sinon on fera autre chose.
                  C'est au code appellant de savoir si ne pas trouver de machin est une erreur (le machin aurait du être là) où une situation normale.

                  Seule la méthode getMachinById() doit connaitre la nomenclature d'un Id

                  Ça c'est un autre problème, si l'ID a une nomenclature particulière et n'accepte pas n'importe quelle valeur il faut que la méthode lance une exception (genre IllegalArgumentException) si la valeur passée est invalide.
                  Mais si la valeur passée est acceptable, il ne faut pas lancer d'exception simplement parce qu'on ne trouve rien.

                  Image la classe Map qui lancerait une exception dans son get simplement parce que la clé donnée n'est pas présente dans le Map (d'autant que certaines implémentations acceptent null en valeur, et peuvent donc retourner null même si la clé est présente).

                  L'argument des performances pour la gestion des exceptions est fallacieux. Les exceptions ça va vite, et bien que ce soit verbeux, c'est lisible.

                  Lancer une exception nécessite de construire le stacktrace de l'endroit qui a lancé l'exception (souvent quelque dizaines de StackTraceElement), ça me semble quand même significativement plus lourd que de simplement retourner null (quand c'est pertinent par rapprot à la sémentique de la méthode) qui ne va allouer aucune mémoire.

                  Les exceptions ne sont pas là pour indiquer que le programme va partir en sucette à partir de maintenant. Elles sont là pour rendre plus clair le déroulement d'un programme.

                  On n'a vraisemblablement pas la même notion de clareté d'un code.
                  • [^] # Re: .

                    Posté par . Évalué à 2.

                    Image la classe Map qui lancerait une exception dans son get simplement parce que la clé donnée n'est pas présente dans le Map (d'autant que certaines implémentations acceptent null en valeur, et peuvent donc retourner null même si la clé est présente).


                    Ok visiblement c'est un problème de goût car l'implémentation de "HashMap" en Python lance une IndexError si la clé n'est pas présente [1] idem pour les "List".

                    Personnellement j'adore, car dans la plupart de mes cas d'utilisation, mon code s'attend a ce que la clé soit présente, ou alors j'ai une valeur par défault.

                    Mais je comprend que les avis puissent diverger.

                    [1] http://www.python.org/doc/faq/general/#how-fast-are-exceptio(...)
                    • [^] # Re: .

                      Posté par (page perso) . Évalué à 3.

                      En Python tu as clairement la séparation:

                      x[clé] accès la valeur associée à la clé, exception s'il n'y a pas d'association

                      x.get(clé [,défaut]) accès à la valeur associée à la clé, retour du défaut s'il n'y a pas d'association

                      x.setdefault(clé [,défaut]) idem et en plus crée l'association clé/défaut s'il n'y en avait pas

                      Ce qui fait que quand tu lis le code, suivant la façon de faire tu sais à quoi t'attendre.

                      Peut-être que les classes Map de Java ont aussi d'autres méthodes d'accès à la sémantique claire.

                      Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

        • [^] # Re: .

          Posté par . Évalué à 2.

          comment tu fais pour sémantiquement indiquer une absence opérationnelle plutôt qu'un cas exceptionnel si tu utilise jamais null ?
      • [^] # Re: .

        Posté par . Évalué à 1.

        Il y a un peu la même chose en C# avec les nullable types :

        int? i; //Nullable int.
        // i.HasValue() == false

        i = 2;
        i.Value; //2

        C'est bien pratique notamment pour le classique tristate (vrai/faux/pas défini).

        Pour la gestion du nul pour il y a aussi l'opérateur "??" (null coalescing operator)
        Le second membre est exécuté si le premier est nul.

        string s = null;
        string s2 = s ?? "Rien"; // s2 == "Rien"
        s = "Un truc";
        string s3 = s ?? "Toujours rien ?"; // s3 == "Un truc"
  • # Sun ?

    Posté par (page perso) . Évalué à 0.

    A mon avis, Sun ne travaille plus sur Java.. Oracle peut-être... faut voir !
  • # On a compris...

    Posté par . Évalué à 4.

    Avant c'était « Javasapusepalibre », maintenant c'est « Javasapuscalacémieu ».

    Eh bien non, je travaille sur Java, comme plus de 18% des développeurs, et pas sur Scala comme plus de 0.43% des développeurs, et Java avait bien besoin d'améliorations.

    Certes ces améliorations sont loin d'être satisfaisantes aux yeux de certains (dont moi, pour être honnête). Mais aux yeux de la plupart des développeurs Java qui ont vu les améliorations du projet Coin, c'est une très bonne chose, et en particulier la gestion automatique des ressources qui était un véritable nid à bugs et à fuites de mémoires.

    Ce que je voudrais, c'est surtout un Java ambitieux et prometteur et si on arrive déjà à Java 7 avec tout ça, c'est pas mal. Restera à avoir Java 8 dans un intervalle maximal de 2 ans avec davantage d'audace.

    Il n'en est pas mention dans l'article, mais une nouvelle API date verra le jour et on sera enfin débarrassé des encombrants Date et Calendar, autres nids à bugs.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.