Java 8 et NetBeans 8 sont disponibles

Posté par  . Édité par Davy Defaud, barmic, j, BAud, ZeroHeure, palm123, Nÿco, domak et Sébastien Koechlin. Modéré par Nÿco. Licence CC By‑SA.
Étiquettes : aucune
31
28
mar.
2014
Java

Oracle a annoncé la mise à disposition de la nouvelle version standard de Java, huitième du nom. Deux ans et sept mois après Java 7, la publication de cette nouvelle version a été retardée afin d’améliorer la sécurité.

Et pour permettre d’exploiter au mieux ce nouveau JDK, une nouvelle version de l’environnement de développement NetBeans est également disponible et porte le même numéro. Côté Eclipse, un correctif est proposé et concernant IntelliJ, Java 8 est pris en charge dans la version 13.1 sortie la semaine dernière.

Ces deux sorties marquent la volonté d’Oracle de convaincre les développeurs.

Sommaire

Nouveautés Java 8

Les lambdas

C’est une technique pour écrire des fonctions qui ne sont pas nommées et directement définies là où elles sont appelées. Cela permet une écriture plus simple pour les fonctions qui ne sont appelées qu’à un seul endroit du code. L’exemple classique est pour définir une fonction de tri :

public class Users {
    public String username;
    public int    karma;

    /**
     * Sort users by karma
     */
    public static void sortUser(Users[] users) {
        Arrays.sort(users, (Users u1, Users u2) -> { return u1.karma - u2.karma; });
    }
}

Avant l’introduction des lambdas, dans cet exemple, il fallait définir une implémentation pour Comparator, ce qui était un peu plus verbeux :

public class Users
{
    public String username;
    public int    karma;

    /**
     * Sort users by karma
     */
    public static void sortUser(Users[] users) {
        Arrays.sort(users, new Comparator<Users>() {
            @Override
            public int compare(Users u1, Users u2) {
               return u1.karma - u2.karma;
            }
         });
    }
}

Interfaces fonctionnelles (FunctionalInterface)

Pour implémenter les lambdas, le langage s’appuie sur les interfaces fonctionnelles, c’est‐à‐dire des interfaces possédant une seule méthode abstraite. Toutes les interfaces respectant cette condition sont, de fait, des interfaces fonctionnelles. Toutefois, il est possible d’utiliser l’annotation @FunctionalInterface pour qu’une erreur soit levée si une interface ne respecte plus cette condition.

API Stream

L’interface de programmation (API) Stream a été ajoutée, permettant de représenter des données sous forme de flux et de les manipuler de manière efficace. Cette API s’appuie largement sur les fonctions lambdas décrites plus haut.

Les habitués des tubes (pipes) du Shell (il y en a par ici ? :)), des langages fonctionnels et de certains autres comme Perl ne devraient pas être trop dépaysés par cette manière de programmer.

Voici un exemple sorti de la documentation officielle :

int sum = widgets.stream()
                 .filter(b -> b.getColor() == RED)
                 .mapToInt(b -> b.getWeight())
                 .sum();

Ici, widgets est une Collection<Widget>, mais cette API peut être utilisée avec toute sorte de flux de données, comme des fichiers ou des sockets. Il est aussi possible de créer ses propres types de flux stream.

Enfin, il est possible de paralléliser les traitements sur ces flux de manière simple (plus simple que gérer des Threads).

Nashorn, JavaScript dans Java

Java inclut désormais un nouveau moteur JavaScript qui remplace le vieillissant Rhino. Il permet donc d’invoquer du code JavaScript directement dans le code Java. Il est évidemment possible d’interagir avec le code Java en appelant du code Java en JavaScript, ou même en étendant des classes Java.

Il est aussi possible de l’utiliser directement en ligne de commande comme un script classique et d’éviter d’écrire un wrapper Java. La commande s’appelle jjs.

Implémentation par défaut dans les interfaces (Defender Methods)

Jusqu’à la version précédente, les interfaces Java ne pouvaient contenir de code, uniquement des déclarations de méthodes. À partir de cette version, les implémentations de méthodes statiques et les implémentations par défaut de méthodes sont possibles. Ces dernières sont des implémentations des méthodes qui seront utilisées si la méthode n’est pas redéfinie dans une autre implémentation qui étend celle‐ci ou une classe qui implémente l’interface sans implémentation pour la méthode.

Cela fait resurgir le problème de l’héritage en diamant qui était évité par l’absence d’héritage multiple de classe et que les interfaces permettaient d’éviter par rapport aux classes abstraites. Que faire lorsqu’une méthode est définie dans plusieurs interfaces implémentées dans une classe ? Prenons l’exemple suivant :

interface A {
    void m() default {}        
}
interface B extends A {}
interface C extends A {}
class D implements B, C {}

Ce cas est assez simple, D héritera de l’implémentation dans A. Si B ou C implémentent la méthode, ce sera cette implémentation qui sera utilisée (l’implémentation la plus spécifique est utilisée). Si B et C implémentent la méthode, il faudrait spécifier explicitement quelle méthode sera utilisée.

Méthodes statiques dans les interfaces

En plus des méthodes par défaut, il est possible de définir des méthodes statiques dans les interfaces. Il n’y a pas de différence avec les méthodes statiques dans une classe.

API Date

Beaucoup de monde attendait une évolution (une révolution ?) de l’interface de programmation (API) Date et utilisait JodaTime à la place de l’API standard.

Java 8 apporte une nouvelle API pour gérer les dates, qui est divisée en deux parties :

  • le temps humain, principalement porté par LocalDate et LocalTime gère une date prenant en compte le fuseau horaire et possédant distinctement différents champs (pour l’heure, le jour, etc.) ;
  • le temps machine, qui est un horodatage (timestamp) et qui s’appuie sur les classes Instant et Duration.

Grande nouvelle : cette nouvelle API est thread-safe ! Je vous laisse découvrir plus en détail cette API au travers du tutoriel de Yohan Beschi, Tutoriel sur les nouveautés du langage 8 : la nouvelle API Date et Time.

Disparition du Permgen

C’est une évolution spécifique à l’implémentation de référence, mais ça fera plaisir à beaucoup de monde en évitant des erreurs du type java.lang.OutOfMemoryError: PermGen space. Le permgen stockait les définitions de classes définies dans le programme en cours, et sa taille pouvait poser un problème pour les grosses applications utilisant beaucoup de classes ou les générant en cours de fonctionnement. C’est donc un point en moins à surveiller pour les mises en production.

Aller plus loin

  • # Vive le progrès!

    Posté par  (site web personnel) . Évalué à 9.

    Python3, C++11, Java 8, Php=>Hack… Tels les bons vins, nos langages préférés se bonifient avec le temps!

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: Vive le progrès!

      Posté par  (site web personnel) . Évalué à 8.

      N’empêche, le nom "Hack" pour le "langage PHP de Facebook" me fait doucement rire…

    • [^] # Re: Vive le progrès!

      Posté par  . Évalué à -2.

      Python3, C++11, Java 8, Php=>Hack… Tels les bons vins, nos langages préférés se bonifient avec le temps!

      C# n'est pas dans la liste puisque ces langages essaient juste de le rattraper.

      • [^] # Re: Vive le progrès!

        Posté par  (site web personnel) . Évalué à 4.

        C# n'est pas dans la liste puisque ces langages essaient juste de le rattraper.

        J'aurais plutôt dit que Javascript n'y était pas, car il est si parfait que le besoin de nouvelles versions ne se fait pas sentir.

      • [^] # Re: Vive le progrès!

        Posté par  (site web personnel) . Évalué à 6.

        On parle de langages libres et non faussés!

        Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

        • [^] # Re: Vive le progrès!

          Posté par  . Évalué à 2.

          Dans ce cas la, pourquoi tu mets Java dans la liste?
          Avec le procès que fait Oracle a Google sur les API..

          • [^] # Re: Vive le progrès!

            Posté par  (site web personnel) . Évalué à 2.

            Parce que l'openjdk sous licence GPL est l'implémentation de référence et qu'Oracle s'est pris un si gros bang bang judiciaire dans le fondement avec du gravier et du verre pilé qu'on est tranquille avec les patent trolls sur Java pour un moment.

            Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

            • [^] # Re: Vive le progrès!

              Posté par  . Évalué à 5.

              Le procès en appel n'est pas encore terminé je crois.

              « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

              • [^] # Re: Vive le progrès!

                Posté par  (site web personnel) . Évalué à 2.

                Je viens de lire ce que Oracle reproche à Google et je suis mitigé: ils leur reprochent d'avoir copier une partie du code source et de la documentation.

                C'est peut être mineur, mais s'ils sont partis de l'openjdk, ce pourrait être une violation de la GPL…

                La dernière partie est intéressante:

                Oracle does not accuse the following of copyright infringement:
                1. Android’s use of the Java programming language.
                2. The names of the API elements, including the names of files, packages, classes, methods, fields, exceptions, and parameters.
                3. The Android source code implementing the APIs contained in the 37 packages, with theexception of rangeCheck and the declarations of the API elements.
                4. The ideas underlying the APIs.
                5. The Dalvik virtual machine (not including the associated class libraries).
                6. Android APIs and associated class libraries other than the accused 37 API packages and
                associated class libraries.
                7. Android source and object code except as listed above.

                http://www.groklaw.net/pdf3/OraGoogle-901.pdf

                Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

                • [^] # Re: Vive le progrès!

                  Posté par  . Évalué à 4.

                  Il avait été établi qu'une petite partie du code source avait été copiée, javadocs, commentaires, et détails d'implementation. Cela touchait très peu de fichiers, moins de 10 si je ne me trompe pas.
                  Le juge avait alors ordonné a Google de remplacer ce code copié par du code propre a Google.

        • [^] # Re: Vive le progrès!

          Posté par  . Évalué à 3.

          On parle de langages libres et non faussés!

          non faussés ??

  • # Quelques commentaires additionnels

    Posté par  . Évalué à 10.

    Avant l’introduction des lambdas, dans cet exemple, il fallait définir une implémentation pour Comparator, ce qui était un peu plus verbeux…

    C’était aussi moins performant car une lambda ne créera pas de classe sous-jacente, d’où pas besoin de charger une classe, pas besoin de passer par un security manager, etc.
    C'est beaucoup plus léger!

    Quelqu'un a un retour sur le mélange des lambdas avec un code définissant des generics? (A ne pas confondre avec un code utilisant les generics, c'est a dire qui parametrise les types)
    Est ce que cela ne fait pas trop de vilain?

    Disparition du Permgen
    Le PermGen est remplace par Metaspace dont la taille n'est pas bornée par défaut, ce qui veut dire qu'elle peut grossir indéfiniment. Les Ops préféreront peut-être la borner avec l'option MaxMetaspaceSize de la JVM HotSpot:
    http://java.dzone.com/articles/java-8-permgen-metaspace

    • [^] # Re: Quelques commentaires additionnels

      Posté par  (site web personnel, Mastodon) . Évalué à -1.

      Je n'aime pas les lambda. Même si c'est pratique, ça brise le principe DRY. Un peu comme un programme en C dans lequel est réimplémente une liste chaînée dans chaque module où c'est nécessaire.

      En C++11, la création de lambda peut entraîner la génération et l'invocation d'un functor si l'inlining n'est pas trivial. Ce n'est pas le cas avec les lambdas Java ?

      • [^] # Re: Quelques commentaires additionnels

        Posté par  . Évalué à 4.

        Je ne vois pas en quoi les lambdas java ne sont pas DRY. Je ne connais pas assez le C++ pour parler de leur équivalent.

        Premièrement les lambdas Java ne sont pas des classes, donc c'est déjà ça en moins.
        Pour l'inlining, ça va être exactement comme tu dis. Une lambda simple va très bien être inlinée par le JIT. Une lambda plus complexe ne le sera probablement pas. J'avais lu que la limite pour que le JIT inline une méthode était quelque chose comme 35 opcodes du bytecode Java.

        • [^] # Re: Quelques commentaires additionnels

          Posté par  . Évalué à 4.

          pour que le JIT inline une méthode était quelque chose comme 35 opcodes du bytecode Java.

          Valeur par défaut oui. Tu peux jouer avec -XX:MaxInlineSize.

        • [^] # Re: Quelques commentaires additionnels

          Posté par  (site web personnel, Mastodon) . Évalué à -1.

          Je me suis certainement mal exprimé : le problème ne sont pas les lambdas en Java : ce sont les lambdas le problème. Que ce soit en JS, en PHP, en C++ ou en Python, je n'utilises jamais les lambdas. Je définis toujours une fonction que je peux tester unitairement et réutiliser plus tard ou ailleurs.

          J'avoue, j'utilises les lambdas pour le prototypage, pour pouvoir écrire mon code en flux tant que je tiens une idée. Après, je nettoie.

          • [^] # Re: Quelques commentaires additionnels

            Posté par  . Évalué à 5.

            Beaucoup de lambda font une instruction. De plus je ne vois pas l'intérêt de tester une méthode action() et une méthode actionAll() si action() ne sert nul part ailleurs. Si tu reste sur des méthodes pas trop longues et que tu utilise pas les lambda pour tout et n'importe quoi, tu ne détectera pas plus rapidement de bug.

            D'un point de vu réutilisation c'est assez subtile et c'est l’expérience qui va parler, mais je ne suis pas pour trop se poser la question de la réutilisation à priori. Avec des tests unitaires bien fait, tu peut te permettre de réorganiser le code au moment où tu en a besoin pour pouvoir appliquer le DRY sans crainte. D'ailleurs il n'y a pas qu'une seule façon de factoriser du code et c'est pas nécessairement la plus intéressante que tu aurais choisi à priori.

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

      • [^] # Re: Quelques commentaires additionnels

        Posté par  . Évalué à 8.

        Mauvais pour le DRY, mais bon pour le DWHLOCFST (Dont Write Hundreds Lines Of Code For Something Trivial) (je viens de l'inventer).

        Please do not feed the trolls

      • [^] # Re: Quelques commentaires additionnels

        Posté par  . Évalué à 10.

        Je n'aime pas les lambda. Même si c'est pratique, ça brise le principe DRY

        Il ne faut pas se focaliser sur les lambdas. Java 8 amène en même temps les lambdas, une API stream et les méthodes reference. Ils marchent ensemble.

        Si tu regardes le style Java moderne c'est déjà ce qu'on utilisait sauf que c'était dégueulasse syntaxiquement.

        Maintenant regardons du côté du DRY. Reprenons mon exemple d'hier

          public Collection<String> lambda(Collection<String> c) {
            return c.stream()
                    .map((s) -> "foo" + s)
                    .collect(Collectors.toList());
          }

        Tu vas dire "foo" + s c'est pas DRY. Ca mériterait d'être défini proprement quelque part pour être réutilisé. Ca tombe bien c'est pour ca que les method references ont été ajoutées en même temps

          static final String addPrefix(String str) {
            return "foo" + str;
          }
        
          public Collection<String> methodHandle(Collection<String> c) {
            return c.stream()
                    .map(Main::addPrefix)
                    .collect(Collectors.toList());
          }

        Voilà c'est magique j'ai maintenant un bout de code nommé et isolé qui défini une opération précise. Avant il fallait instancier une fonction statique à la Guava. C'est plus clair et plus performance.

        Maintenant tu vas me dire que c'est cool tant que ton opération à effectué ne dépend que de l'élément lui même. Ca ne marche pas si tu dois paramétrer l'opération avec quelque chose d'autre. Reprenons depuis le début.

          public Collection<String> lambdaWithCustomPrefix(Collection<String> c, String prefix) {
            return c.stream()
                    .map(s -> prefix + s)
                    .collect(Collectors.toList());
          }

        Retour à la case départ j'ai une lambda que je ne pourrais pas réutiliser et qui n'est pas définie précisément. Dans ce cas la solution method reference ne marche pas car que je peux pas passer mon paramètre supplémentaire. Je peux bidouiller avec le stream API mais c'est pas une bonne idée en soit. Du coup on peut faire quelque chose qui ressemble à ce qu'on faisait avant avec une classe:

          static class PrefixAdder implements  Function<String, String> {
            private final String prefix;
        
            PrefixAdder(String prefix) { this.prefix = prefix; }
        
            @Override
            public String apply(String str) { return prefix + str; }
          }
        
          public Collection<String> classWithCustomPrefix(Collection<String> c, String prefix) {
            return c.stream()
                    .map(new PrefixAdder(prefix))
                    .collect(Collectors.toList());
          }

        Ok ca marche c'est propre à l'appel mais la déclaration est un peu verbeuse. Et ce que je viens d'écrire ca ressemble fortement à une fonction currifiée non ? Java n'est pas fonctionnel pour un sous mais est ce que je pourrais définir une fonction avec un invocation partielle ? Essayons

          Function<String, Function<String, String>> partialPrefixAdder = prefix -> str -> prefix + str;
        
          public Collection<String> currifyWithCustomPrefix(Collection<String> c, String prefix) {
            return c.stream()
                    .map(partialPrefixAdder.apply(prefix))
                    .collect(Collectors.toList());
          }

        Oui c'est donc possible. La syntaxe pique les yeux et je suis pas certain que je l'utiliserais en Java mais ca marche.

        Donc oui les lambdas utilisée comme un gros bourrin c'est pas DRY. Maintenant si tu regardes la solution dans son ensemble et que tu branches ton cerveau c'est un très bon outil. lambda pour des trucs qui n'ont pas de sens en dehors de ce traitement précis. Unitée logique nommées pour les opérations réutilisables. L'ajout de Java 8 c'est l'API du stream et les interfaces fonctionnelles. À la limite on aurait presque pu se passer des lambdas.

        Après Java reste Java, ca fait pas grand chose de plus que ce que j'ai décris et t'es loin de Scala par exemple.

        • [^] # Re: Quelques commentaires additionnels

          Posté par  (site web personnel, Mastodon) . Évalué à 1.

          Je suis heureux de voir que les développeurs Java ont découverts les pointeurs de fonctions membre :-D

          L'explication est intéressante, merci.

          • [^] # Re: Quelques commentaires additionnels

            Posté par  . Évalué à 3.

            Je suis heureux de voir que les développeurs Java ont découverts les pointeurs de fonctions membre :-D

            Houla ne t’emballe pas. Ça va prendre encore quelques années et des montagnes d'horreurs pour en arriver là. En 2014 ils ont pas encore assimilé toute la masse, koff, des changements de Java 7 et sont tellement tout fou devant la révolution qu'est Guava, qu'ils en foutent 20 couches que tu comprends plus rien, que ça fait mal aux yeux et qu'ils font exactement ce que la doc de Guava dit de ne pas faire :)

            Le chemin va être long… Par contre y'a plein d'opportunité à prendre pour réécrire des libs avec les nouvelles possibilités. Ca bouge un peu partout et c'est marrant. Tu vois aussi les binding des projets multi-langage sur la JVM devenir plus proche, Java étant toujours l'exception pourrie précédemment.

        • [^] # Re: Quelques commentaires additionnels

          Posté par  . Évalué à 4.

          C'est sympa ton exemple sur la curryfication, je ne pensais pas que les lambdas pouvaient le faire.
          Merci!

  • # Fin de la pureté de Java

    Posté par  (site web personnel) . Évalué à -1.

    J'ai comme l'impression que c'est, pour des raisons pragmatiques, la fin de la pureté de Java comme langage orienté objet.

    Des lambda qui ne créent pas de classe : ça manquait, c'est clair. Mais en introduisant des fonctions, qu'elles soient anonymes ou non d'ailleurs, détachées de toute classe, ce n'est plus purement objet du coup.

    Au passage, j'ignorais qu'il était possible de construire un objet et de surcharger une méthode pour cette instance, c'est curieux, et pas vraiment élégant non plus.

    Des interfaces où on peut mettre du code : c'est quoi cette horreur, et ça sert à quoi ? Évidemment que ça introduit un problème d'héritage en losange…

    • [^] # Re: Fin de la pureté de Java

      Posté par  . Évalué à 8.

      Au passage, j'ignorais qu'il était possible de construire un objet et de surcharger une méthode pour cette instance, c'est curieux, et pas vraiment élégant non plus.

      T'as pas du coder des masses en Java alors… C'est, je trouve, plus élégant que les classes définies in extenso et utilisées qu'une seule fois

    • [^] # Re: Fin de la pureté de Java

      Posté par  . Évalué à 10.

      J'ai comme l'impression que c'est, pour des raisons pragmatiques, la fin de la pureté de Java comme langage orienté objet.

      Je pense que tu n'as aucune idee de comment sont implementées les lambdas dans Java 8.

      Les méthodes ne sont toujours pas des objets de premier ordre et les fonctions ne sont pas anonymes. Ce sont juste de interface fonctionelle (SAM). C'est juste du sucre syntaxique quoi avec un gros boulot dans la JVM pour que ca rame pas trop.

      Des interfaces où on peut mettre du code : c'est quoi cette horreur, et ça sert à quoi ? Évidemment que ça introduit un problème d'héritage en losange…

      Ca existe dans beaucoup d'autres langages ca se nomme un trait. En Java 8 tu as des traits stateless qui limites très fortement leur interet. Ca permet juste de pas péter des API quand tu as besoin de les faire évoluer.

      Les trait sont en général utiles pour introduire de la composition et faciliter la réutilisation. Ca peut introduire quelque probleme mais en general ca en resoud plus que ca en introduit.

      • [^] # Re: Fin de la pureté de Java

        Posté par  (site web personnel) . Évalué à -3.

        Les méthodes ne sont toujours pas des objets de premier ordre et les fonctions ne sont pas anonymes. Ce sont juste de interface fonctionelle (SAM). C'est juste du sucre syntaxique quoi

        Carrément pas. Sauf erreur de ma part, jusqu'à présent il n'existait pas de fonctions détachées des classes; était impossible de passer une méthode en argument d'une fonction. C'est plus qu'un changement de syntaxe ici, c'est une sortie du paradigme d'origine.

        • [^] # Re: Fin de la pureté de Java

          Posté par  . Évalué à 8.

          import java.util.Arrays;
          
          public class Main {
          
              public static void main(String[] args) {
          
                  System.out.println(
                          Arrays.asList(args).stream()
                                  .map((input) -> "foo" + input)
                                  .toArray()
                  );
              }
          }

          La signature de map est:

          <R> Stream<R> map(Function<? super T, ? extends R> mapper);

          Function est une SAM puisque seul R apply(T t); n'est pas implémentée.

          Si tu regardes du côté de l'implémentation de tout ca, c'est actuellement fait comme ca:

          /javap -c -p Main.class
          Compiled from "Main.java"
          public class Main {
            public Main();
              Code:
                 0: aload_0
                 1: invokespecial #1                  // Method java/lang/Object."<init>":()V
                 4: return
          
            public static void main(java.lang.String[]);
              Code:
                 0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
                 3: aload_0
                 4: invokestatic  #3                  // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
                 7: invokeinterface #4,  1            // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
                12: invokedynamic #5,  0              // InvokeDynamic #0:apply:()Ljava/util/function/Function;
                17: invokeinterface #6,  2            // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
                22: invokeinterface #7,  1            // InterfaceMethod java/util/stream/Stream.toArray:()[Ljava/lang/Object;
                27: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
                30: return
          
            private static java.lang.String lambda$0(java.lang.String);
              Code:
                 0: new           #9                  // class java/lang/StringBuilder
                 3: dup
                 4: invokespecial #10                 // Method java/lang/StringBuilder."<init>":()V
                 7: ldc           #11                 // String foo
                 9: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
                12: aload_0
                13: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
                16: invokevirtual #13                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
                19: areturn
          }
          

          La raison a très bien été expliquée dans un talk du JVM language submit. C'est assez similaire a ce qui aux bridges methods qui ont été fait pour les generics dans Java 5.

          Maintenant en pratique ca fait des années quoi se balade des lambda illisible de avec 7 lignes de boilerplate et un gros coup d'exec. C'était tellement ridicule que les IDE détectaient les patterns
          lambda et les affichaient avec la syntax 8 pour que ca soit lisible…

      • [^] # Re: Fin de la pureté de Java

        Posté par  . Évalué à 2.

        En Java 8 tu as des traits stateless qui limites très fortement leur interet.

        Je voyais surtout ça pour des SAM sophistiquées, j'ai pas d'exemple qui me viens à l'esprit mais tu définit une méthode de l'interface via une lambda et l'utilisateur a une panoplie de méthodes.

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

        • [^] # Re: Fin de la pureté de Java

          Posté par  . Évalué à 2. Dernière modification le 28 mars 2014 à 20:20.

          Oui les default methods ont clairement été faite pour cela, permettre de faire évoluer les veilles API sans tout casser. L'ajout des lambda demandait d'introduire des méthodes dans des classes existantes. Leur solution n'est pas trop folle.

          Maintenant en pratique on peut voir ca comme des traits stateless. Scala a des traits stateful de son côté. Il y a six mois, Guillaume Laforge disait y reflechir pour Groovy mais ne savait pas trop de quel côté il allait pencher. Je sais pas si ca a bougé.

          Pour ceux qui sont intéressé sur par les lambda et les défaut méthodes voici quelques liens qui peuvent être intéressants:

          State of the lambda
          Translation of lambda expressions
          Les autres workings document du projet Open JDK

          Conf: Les bridges méthodes pour l'implémentation des default methods
          Conf: Benchmark des lambdas

          Le deux présentations sont dispo au téléchargement .

          Vu le champ de mine que c'était ils ont fait du bon boulot. Faire évoluer ce truc avec les contraintes qu'ils ont c'est l'enfer. Bon y'a encore du boulot pour 3 ou 4 releases comme ca :)

          Au passage c'est pas le sujet, mais le talk d'Aleksey Shipilev sur JVM Benchmarking. Il vulgarise très bien son travail sur JMH et la méthodologie.

          • [^] # Re: Fin de la pureté de Java

            Posté par  . Évalué à 3. Dernière modification le 29 mars 2014 à 10:58.

            Les default methods sont clairement la pour pouvoir faire évoluer les interfaces sans casser la compatibilité au niveau source et binaire.
            Avant ça, l’évolution des interfaces suivait 2 approches:

            • A la JDBC: changements cassant l'API, nécessitant de fournir des drivers différents pour chaque version du JDK. C'est deja bien gere par les fournisseurs de base de données, et le default methods ne vont probablement pas résoudre ce problème puisque les fournisseurs de drivers devront quand même fournir 2 versions supportant les specificite de chaque version.

            • A la Eclipse: Publier une interface IMyInterface, puis itérer lorsque des ajouts sont nécessaires: IMyInterface2 extends IMyInterface, IMyInterface3 extends IMyInterface2, etc.

            Bref, c'est pas top, quoique la méthode d'Eclipse a l'avantage de toujours garder la compatibilité ascendante, au prix d'une verbosité et d'une lourdeur sans pareille (même pour du Java).
            Les default methods vont résoudre le problème de l’évolution d'interfaces a la Eclipse.

            • [^] # Re: Fin de la pureté de Java

              Posté par  . Évalué à 2.

              J'ai oublie de dire qu'on dirait que les default methods soient un effet de bord de l'introduction des lambdas qui modifie les interfaces de l'API collection,
              Ces interfaces ont ete implementees de nombreuses fois et ces implementations alternatives sont souvent très utilisées.
              Ils ne pouvaient pas se permettre de casser la compatibilité ascendante.

              • [^] # Re: Fin de la pureté de Java

                Posté par  . Évalué à 2.

                Il me semble qu'on dit exactement la même chose ;)

                Maintenant en pratique, ça revient à conclure que l'approche interface n'était pas une bonne solution pour permettre à un système d'évoluer et que la composition de trait/mixin est bien plus flexible. Bien évidement on a gardé les anciens noms et principes.

                Vu que ça répond au besoin et qu'il y a sûrement des implications techniques ils se sont arrêtés aux traits stateless. Si quelqu'un a un lien sur une discussion à ce sujet où sur l'exploration des deux approches ça m'intéresse. En tant que dev, les traits de Scala sont très pratiques pour composer des comportement; avec du stateless tu es très vraiment limité c'est dommage de ne pas avoir cette possibilité. Mais c'est un premier pas.

    • [^] # Re: Fin de la pureté de Java

      Posté par  (site web personnel) . Évalué à 10.

      J'ai comme l'impression que c'est, pour des raisons pragmatiques, la fin de la pureté de Java comme langage orienté objet.

      Que des lambdas impures abreuvent nos fonctions!

      Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

      • [^] # Re: Fin de la pureté de Java

        Posté par  (site web personnel) . Évalué à 2.

        Est-ce qu'une lambda est une fonction pure ? Ça dépend de si les types sont mutables c'est ça ?

        • [^] # Re: Fin de la pureté de Java

          Posté par  . Évalué à 4.

          À ce que je comprend, une fonction est fonctionnellement pure quand elle n'a pas d'effet de bord et que son résultat n'est pas le produit d'un effet de bord. Donc on peut écrire des fonctions pures avec un langage impur.

          Mais Tanguy parle ici de pureté dans le sens de "purement orienté objet". Dire que Java est purement orienté objet reviendrai à dire "tout est objet". Ce qui n'est pas recevable (les types primitifs ne sont pas des objets).
          Question : un langage à prototypes¹ serait-il plus pur qu'un langage orienté objet classique², vu qu'il n'y a pas de classe mais que les objets peuvent hériter d'autres objets ?

          ¹ Comme par exemple Lua, Javascript, …
          ² Langage à classes : Java, C++, …

    • [^] # Re: Fin de la pureté de Java

      Posté par  (site web personnel) . Évalué à 10.

      J'ai comme l'impression que c'est, pour des raisons pragmatiques, la fin de la pureté de Java comme langage orienté objet.

      Java n'a jamais été pur niveau orienté objet.
      Donc ça ne change pas grand chose, entre presque pur et presque-presque pur, on n'est plus à deux exceptions près. ;)

      • [^] # Re: Fin de la pureté de Java

        Posté par  . Évalué à 9.

        on n'est plus à deux exceptions près.

        Surtout en Java.

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Fin de la pureté de Java

          Posté par  (site web personnel) . Évalué à 4.

          S'ils pouvaient en faire deux de plus pour gérer les "structs à la C" et les types de base dans les generics (et pas via ces horribles wrappers Integer, Float &co), ce serait super!

          L'objet pur, c'est bien, les perfs, c'est mieux!

          Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

          • [^] # Re: Fin de la pureté de Java

            Posté par  . Évalué à -2.

            Personnellement, plutôt que permettre les types de base dans les generics, je préfèrerais qu'ils retirent les types de base au profit des classes wrapper actuellement utilisées. Le plus gros problème : ça casse la compatibilité.

            Mais si ça se faisait, rien n'empêcherait le compilateur au besoin d'utiliser directement les types de base dans le bytecode tant qu'il a la garantie que la variable ne peut être null, sans que ça soit au développeur de se poser la question. D'ailleurs, ma connaissance de javac et du bytecode Java est au mieux parcellaire, mais ça ne m'étonnerait même pas qu'il s'agisse d'une optimisation déjà existante…

            • [^] # Re: Fin de la pureté de Java

              Posté par  . Évalué à 2.

              Mais si ça se faisait, rien n'empêcherait le compilateur au besoin d'utiliser directement les types de base dans le bytecode tant qu'il a la garantie que la variable ne peut être null, sans que ça soit au développeur de se poser la question. D'ailleurs, ma connaissance de javac et du bytecode Java est au mieux parcellaire, mais ça ne m'étonnerait même pas qu'il s'agisse d'une optimisation déjà existante…

              Heureusement, la JVM sait déjà faire ça bien sur sinon les codes numériques auraient des perfs très très très mauvaises…

              • [^] # Re: Fin de la pureté de Java

                Posté par  . Évalué à 6.

                Heureusement, la JVM sait déjà faire ça bien sur sinon les codes numériques auraient des perfs très très très mauvaises…

                Non la JVM ne sait pas faire ça. Tu n'as pas un système de type unifié et les deux mondes sont clos et ne communique que par un système de boxing couteux et dangereux. Les performances des Integer/Long sont désastreuses et leur occupation mémoire démentielle.

                On peut faire un benchmark très simple. On va faire la somme d'un tableau d'int puis d'Integer. La troisième variante c'est d'utiliser un Long au lieu d'un long pour maintenir la somme

                @OutputTimeUnit(TimeUnit.SECONDS)
                @State(Scope.Benchmark)
                public class MyBenchmark {
                
                  static final int SIZE = 1_000_000;
                
                  int[] intArray =  IntStream.range(0, SIZE).toArray();
                
                  Integer[] integerArray = IntStream.range(0, SIZE).boxed()
                          .collect(Collectors.toList())
                          .toArray(new Integer[SIZE]);
                
                  @GenerateMicroBenchmark
                  public long testPrimitive() {
                    long sum = 0;
                    for (int i = 0; i < intArray.length; i++) {
                      sum += intArray[i];
                    }
                
                    return sum;
                  }
                
                  @GenerateMicroBenchmark
                  public long testBoxed() {
                    long sum = 0;
                    for (int i = 0; i < integerArray.length; i++) {
                      sum += integerArray[i];
                    }
                
                    return sum;
                  }
                
                  @GenerateMicroBenchmark
                  public long testBoxed2() {
                    Long sum = 0L;
                    for (int i = 0; i < integerArray.length; i++) {
                      sum += integerArray[i];
                    }
                
                    return sum;
                  }
                
                  public static void main(String[] args) throws RunnerException {
                    Options opt = new OptionsBuilder()
                            .include(".*" + MyBenchmark.class.getSimpleName() + ".*")
                            .forks(1)
                            .warmupIterations(5)
                            .measurementIterations(5)
                            .build();
                
                    new Runner(opt).run();
                  }

                Voilà le resultat

                Benchmark                         Mode   Samples         Mean   Mean error    Units
                o.s.MyBenchmark.testBoxed        thrpt         5      430.597       15.005    ops/s
                o.s.MyBenchmark.testBoxed2       thrpt         5      120.147        8.491    ops/s
                o.s.MyBenchmark.testPrimitive    thrpt         5     3341.320      502.704    ops/s
                

                C'est dix fois plus lent. Et encore dans ces microbenchmark tu ne paies pas le coup du GC qu'une vraie appli a. Entre testBoxed et testBoxed2 une majuscule de différence te rend presque encore 4x plus lent.

                Bref actuellement tu as le choix de faire plaisir au programmeur ou au programme… Sachant que ces problèmes remontent jusque dans les API du JDK. Tu as certaines choses de l'API de stream que tu ne peux pas faire pour des int par ce qu'il n'y a pas de type spécialisés.

                Certain langages sur la JVM ont un système de type unifié, que la JVM n'a pas, et ont un mécanisme de spécialisation pour essayer que ça ne soit pas trop désastreux en perf. Mais ça doit pas être si trivial par ce qu'on arrive très vite aux limites et tu repasses dans le monde slow-motion assez facilement.

                Bref si tu veux faire du Java performant et réussir à tenir plus de 4 entiers en mémoire tu restes sur les types primitifs et tu utilises les structures de données spécialisées trove par exemple. Oracle avait dans sa roadmap un système de type unifié pour Java 9 ou 10 mais pas vu une seule discussion depuis les talks de 2012. En attend pour tout ce qui est sérieux tu reste aux types primitifs et tu pleures sur l'API du JDK.

                D'un autre côté ca pousse très dur sur la perf en ce moment avec le retour en force des FFI, du off-the-heap, du code à la C par nos amis traders haute fréquence et base de données distribuées. Ça va être rigolo de voir comment ils vont s'en sortir chez OpenJDK :)

                • [^] # Re: Fin de la pureté de Java

                  Posté par  (site web personnel) . Évalué à 1.

                  Il y a un truc qui n'apparaît pas dans ton benchmark, c'est que les Integer ont un cache: le boxing va retourner la même instance d'Integer pour un int de la même valeur, entre certaines bornes, et c'est configurable (http://stackoverflow.com/questions/15052216/how-large-is-the-integer-cache). C'est clair que ça reste limité, mais en pratique je pense qu'on y gagne pas mal.

                  Autrement l'approche de Scala me semble la plus pragmatique: au niveau du langage il y a des types correspondants aux types primitifs de Java (Int, Long, etc.), mais qui se comportent comme des classes, ont leur propres méthodes, sont utilisables dans les types génériques. Le compilateur se débrouille après pour utiliser les types primitifs au niveau du bytecode (donc pas plus d'overhead).

                  • [^] # Re: Fin de la pureté de Java

                    Posté par  . Évalué à 2.

                    Autrement l'approche de Scala me semble la plus pragmatique: au niveau du langage il y a des types correspondants aux types primitifs de Java (Int, Long, etc.), mais qui se comportent comme des classes, ont leur propres méthodes, sont utilisables dans les types génériques. Le compilateur se débrouille après pour utiliser les types primitifs au niveau du bytecode (donc pas plus d'overhead).

                    Ok pour la praticité pour le programmeur.
                    Mais justement je me demande en quoi les compilateur Scala ferait mieux que le compilateur Java?
                    L’exécution se faisant sur la JVM pour les deux langages, les problèmes de perfs de l'un devraient se retrouver également avec l'autre.

                  • [^] # Re: Fin de la pureté de Java

                    Posté par  . Évalué à 3.

                    Il y a un truc qui n'apparaît pas dans ton benchmark, c'est que les Integer ont un cache: le boxing va retourner la même instance d'Integer pour un int de la même valeur, entre certaines bornes, et c'est configurable (http://stackoverflow.com/questions/15052216/how-large-is-the-integer-cache). C'est clair que ça reste limité, mais en pratique je pense qu'on y gagne pas mal.

                    Ca ne change rien sur la perf. Ca permet de ne pas créer trop d'objets, et donc diminuer un peu l'empreinte mémoire et la pression sur le GC, pour les valeurs les plus courantes mais le coût d’exécution est le même. De toute facon si la perf est ton problème, le cache sera toujours beaucoup trop petit.

                    Autrement l'approche de Scala me semble la plus pragmatique: au niveau du langage il y a des types correspondants aux types primitifs de Java (Int, Long, etc.), mais qui se comportent comme des classes, ont leur propres méthodes, sont utilisables dans les types génériques. Le compilateur se débrouille après pour utiliser les types primitifs au niveau du bytecode (donc pas plus d'overhead).

                    Je n'écris plus beaucoup de Scala ces derniers temps mais si l'approche semble en effet plus propre, le mécanisme de spécialisation arrive assez vite à ses limites et tu as donc des performances assez imprédictibles pour qui ne sait précisément l'implémentation derrière. Je ne connais pas suffisamment la théorie derrière pour savoir si c'est un problème d'engineering ou théorique.

                    Du côté de la JVM, on parlait informellement en 2012 d'optimisations pour détecter une suite de box/unbox pour les virer. Identiquement théoriquement je ne sais pas si c'est une jambe de bois.

                    À ma connaissance aucun langage sur la JVM n'a vraiment résolu le problème et donc que la JVM est le facteur limitant.

                    • [^] # Re: Fin de la pureté de Java

                      Posté par  (site web personnel) . Évalué à 2.

                      En fait allouer (beaucoup) d'objets a un impact sur la performance en plus de l'espace utilisé: en tout cas dans les systèmes multi-threadé à cause des garanties offertes par le Java Memory Model, il y a une Write barrier à chaque exécution d'un constructeur. J'avais lu à l'époque une publication sur le sujet qui montrait l'impact que cela pouvait avoir et promouvait le recyclage d'objets à la place de leur destruction par le garbage collector.

                      • [^] # Re: Fin de la pureté de Java

                        Posté par  . Évalué à 4.

                        Je pense qu'on s'écarte un peu du sujet initial. Évidement utiliser des objets plutôt que des types primitives à un fort impact sur les performances pour les raisons suivantes:

                        • Coût du cycle de vie d'un objet
                        • Empreinte mémoire très supérieure qui pourrie tes caches et te fais faire deux fois plus de fetch
                        • Tu perds la localité d'accès, le pattern d'accès mémoire est moins clean et le proco va avoir plus de mal
                        • Avoir beaucoup d'objets implique que GC te bouffe du CPU et te nique tes caches
                        • Etc.

                        Avoir un cache d'objets pour les entiers ne résout pas ces problème et de toute façon quand ces problèmes commence à se poser c'est que ton cache devrait faire 232 éléments pour des int… Et ton pattern d'accès mémoire est toujours pourri.

                        Maintenant oui faire des pools d'objets ou des flyweight ca à un sens dans des cas déterminé. Suffit de regarder ce qui a été fait par twitter pour Netty 4.

                        en tout cas dans les systèmes multi-threadé à cause des garanties offertes par le Java Memory Model, il y a une Write barrier à chaque exécution d'un constructeur.

                        Tu as une source. Par ce que AFAIK (et le cookbook de la JSR 133 confirme) en sortie de constructeur c'est une barrière StoreStore qui est requise, et StoreStore sur x86 c'est un No-op vu que c'est déjà garanti par le memory model d'X86…

                        • [^] # Re: Fin de la pureté de Java

                          Posté par  (site web personnel) . Évalué à 1.

                          On est d'accord que le cache d'objets ne résout pas tout, mais faire un bench qui tombe dans le pire cas reste un peu biaisé. En réutilisant les objets, on gagne quand même quelque chose.

                          En fait mes souvenirs datant un peu, c'est plus des effets de cache lors de l'initialisation des objets qui ont un effet sur les perfs sur les machines multi-cores. C'est décrit dans une publication que j'avais lue à l'époque (désolé je n'ai pas trouvé de lien en accès ouvert).

                        • [^] # Re: Fin de la pureté de Java

                          Posté par  (site web personnel) . Évalué à 1.

                          On est d'accord que le cache d'objets ne résout pas tout, mais faire un bench qui tombe dans le pire cas reste un peu biaisé. En réutilisant les objets, on gagne quand même quelque chose.

                          En fait mes souvenirs datant un peu, c'est plus des effets de cache lors de l'initialisation des objets qui ont un effet sur les perfs sur les machines multi-cores. C'est décrit dans une publication que j'avais lue à l'époque (désolé je n'ai pas trouvé de lien en accès ouvert).

                      • [^] # Re: Fin de la pureté de Java

                        Posté par  . Évalué à 2. Dernière modification le 02 avril 2014 à 10:28.

                        J'avais lu à l'époque une publication sur le sujet qui montrait l'impact que cela pouvait avoir et promouvait le recyclage d'objets à la place de leur destruction par le garbage collector.

                        Ça expliquerait pourquoi les gars de Grizzly s'amusent a réutiliser les objets HTTPServletRequestImpl et a les relâcher agressivement en faisant disparaître les données dont tu j'avais besoin plus tard :)

                        Concrètement je n'ai jamais vu de preuve montrant que cela améliorait les perfs, ou bien même que ça les dégradait. Peut être que ça effectivement du sens pour un serveur web avec énormément d’opérations par seconde.

                        Quoiqu'il en soit, je me demande si de telles techniques ont été utilisées a une époque ou la JVM était moins performante ?

                        • [^] # Re: Fin de la pureté de Java

                          Posté par  . Évalué à 2.

                          En Java je ne sais pas, mais au niveau système, Linux a tendance à recycler la mémoire allouée par brk (donc des données qui tiennent dans moins d'une page) plutôt que passer par l'allocation depuis une nouvelle page (pour des raisons de perfs évidentes). En fait, tout un tas « d'allocateurs de petits objets » ont été proposés par le passé pour plusieurs plates-formes, comme par exemple dans Modern C++ Design, où Alexandrescu décrit un allocateur de ce genre qui exploite les capacité du « placement new ».

                • [^] # Re: Fin de la pureté de Java

                  Posté par  . Évalué à 2.

                  Je ne pensais pas a ce genre de code mais a des trucs beaucoup plus bêtes avec des variables locales qui mixent allègrement boxing et unboxing.
                  Mais en voyant ton benchmark, je me dis que l'optimisation a lqauelle je pensais reste forcement limitée et que ça gêne le calcul numérique.

                  Au passage, c'est sympa JMH, je ne connaissais pas.
                  Du coup je me demande si la JVM ne fait pas des optimisations spéciales pour le tableau d'int ? Loop unrolling, etc.

                  • [^] # Re: Fin de la pureté de Java

                    Posté par  (site web personnel) . Évalué à 1.

                    Pour les optimisations, oui très certainement, le JIT de java (HotSpot Server, donc celui d'Oracle) est très performant et implémente les optimisations "standards" : optimisation des boucles, inlining de méthodes "agressif" (les méthodes non finales et non encore surchargées sont "inlinées" avec une potentielles désoptimisations aux cas où ça ne tiendrait plus), analyse SSA pour register allocation, etc. Si bien que plus grand monde ne cherche à optimiser drastiquement le bytecode, mais cherche plutôt à le produire de manière à faciliter la tâche au JIT…

                    P.S. : sur une JDK compilée en debug il y a des options pour voir ce que fait le JIT, -XX:+PrintCompilation et -XX:+PrintInlining ou quelque chose comme ça.

                    • [^] # Re: Fin de la pureté de Java

                      Posté par  . Évalué à 2.

                      Tu n'as pas besoin d'un build fastdebug, c'est une option product. Par contre il te faut le module hsdis dans ton JDK ou dans ton LD_LIBRARY_PATH. Pour savoir si une option est product ou release il suffit d'aller voir dans le fichier `src/share/vm/runtime/globals.hpp' d'Hotspot.

                      Pour la marche a suivre c'est la.

          • [^] # Re: Fin de la pureté de Java

            Posté par  . Évalué à 3.

            S'ils pouvaient en faire deux de plus pour gérer les "structs à la C" et les types de base dans les generics (et pas via ces horribles wrappers Integer, Float &co), ce serait super !

            Oui, les structs a la C ou meme C# sont un sujet chaud en ce moment. Beaucoup de monde le demande. C'est peut-être l'effet d'Android qui a amené beaucoup plus de programmeurs de jeux que le Java Desktop ?
            Bref, il me semblent qu'ils parlent d'un truc comme ça pour Java 9 avec les Value Objects: http://openjdk.java.net/jeps/169

            Par ailleurs, il me semblait avoir entendu qu'ils optimisaient déjà les collections avec les types primitifs via des intrinsics dans la JVM (pattern de code recevant une optimisation spéciale), ou bien que c’était en projet. Je ne me rappelle plus exactement.

            • [^] # Re: Fin de la pureté de Java

              Posté par  . Évalué à 3.

              Comme j'ai pas fait de Java depuis un bail, j'avais du mal à piger où se situait le problème. De ce que j'ai pu comprendre, le problème d'une « struct » Java serait le suivant :

              public class Toto {
                  public int a;
                  public char [] str = new char[MAX];
                  public Titi t = new Titi();
              }

              Alors qu'en C on écrirait tout bêtement :

              struct toto_s {
                  int a;
                  char str[MAX];
                  struct titi t;
              };

              Du coup j'en déduis que lorsqu'on parle des « structs à la C », on veut parler de la façon d'allouer de façon contiguë la mémoire (et ce, de façon garantie). J'ai bon ? Si oui, j'ai du coup j'ai une question subsidiaire : il me semble relativement trivial pour un compilateur d'estimer l'espace pris par un objet uniquement composé de données. Même "Titi.class" pourrait être annoté directement par le compilateur pour indiquer qu'il n'y a pas de méthodes définies.

              Du coup, a-t-on réellement besoin d'un « type » qui soit explicitement des structs « à la C » ?

              • [^] # Re: Fin de la pureté de Java

                Posté par  . Évalué à 2.

                Avec des références str et t qui s'échappent, ça ne va pas être facile…

                Ensuite si tu prends le cas de C++, la contiguïté de la mémoire est fortement liée aux constructeurs, opérateurs de copie…, qu'est-ce qui se passerait en java pour =, ==, equals…?

                Que se passerait-il si tu avais mis Toto à la place de Titi ?

                Je pense qu'on aurait réellement besoin d'une structure spécifique dans le langage.

                • [^] # Re: Fin de la pureté de Java

                  Posté par  . Évalué à 2.

                  Oui, le fait que tout soit référence est embêtant de ce côté (d'ailleurs, tout habitué que je suis à C++, j'avais oublié de faire new au début, oubliant la référence nulle de départ), et effectivement la copie est ce qui pose problème.

                  Pour reprendre mon exemple :

                  public class Toto {
                      public int a;
                      public char [] str = new char[MAX];
                      public Titi t = new Titi();
                  }

                  Dans ce cas précis, tout est connu à la compilation, et donc le compilateur pourrait allouer sur le tas un sizeof(int)+sizeof(char)*MAX+sizeof(Titi). Par contre, si j'instancie une "struct" toto, puis que je la passe en paramètre, ou que je l'utilise pour initialiser l'attribut d'un objet, etc., je me retrouve à passer sa référence. Donc il faut explicitement fournir une méthode/une fonction de clonage.

                  En ce qui concerne le ==, je ne vois pas trop le problème en Java. On n'utilise plus .equals de nos jours ?

                  • [^] # Re: Fin de la pureté de Java

                    Posté par  . Évalué à 1.

                    Dans un bon article sur l'escape analysis tu trouveras certainement plus de détails sur le pourquoi du comment.

              • [^] # Re: Fin de la pureté de Java

                Posté par  . Évalué à 2.

                Du coup, a-t-on réellement besoin d'un « type » qui soit explicitement des structs « à la C » ?

                Je crois que le principe fondamental c'est qu'en Java mis à part les types primitifs et les références elles-même tout est alloué sur le tas. Donc tu n'a rien comme info sur la position en mémoire (et je crois que ça permet au gc de déplacer les objets pour faire un compactage de la mémoire).

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

                • [^] # Re: Fin de la pureté de Java

                  Posté par  . Évalué à 2.

                  Oui, tout objet est alloué sur le tas, mais ça ne veut pas dire que lors de l'instanciation d'un objet « pur données », le compilateur n'est pas capable d'en déterminer sa taille et d'allouer juste ce qu'il faut. En d'autres termes, si j'étais en C++, je pourrais faire un truc du genre (pas du tout efficace, mais pour montrer l'idée) :

                  // Allocation de tous les membres d'une structure sur le tas.
                  size_t   total_size = sizeof(int) + MAX*sizeof(wchar_t) + sizeof(Titi);
                  void*    memory     = operator new (total_size);
                  wchar_t* str        = new((char*)memory+sizeof(int)) wchar_t[MAX];
                  Titi*    t          = new((char*)memory+sizeof(int)+sizeof(wchar_t)*MAX) Titi;
                  
                  // ...
                  
                  *reinterpret_cast<int*>(memory) = 1;
                  *reinterpret_cast<wchar_t*>((char*)memory+sizeof(int))[0] = 'a';
                  *reinterpret_cast<Titi*>((char*)memory+sizeof(int)+MAX*sizeof(wchar_t)).someField = ...;
              • [^] # Re: Fin de la pureté de Java

                Posté par  . Évalué à 2. Dernière modification le 02 avril 2014 à 10:20.

                De ce que je comprends, les problèmes sont:

                • Les allocations multiples pour tous les objets dans ta classes, et la gestion individuelle de chacun de ces objets avec les problèmes de synchronisation, GC, etc.

                • Les multiples références qui ralentissent l’exécution du code (déréférencements a faire)

                • L’impossibilité de profiter des instructions vectorielle des processeur pour travailler avec des nombres très grands (> 64 bits, qui est le type "long" en Java, le plus grand géré par la JVM)

                Ajouter des value objects permettrait de gérer de tels objets comme un tout ce qui permettrait de boxer/unboxer toute la structure d'un coup au lieu de le faire un champ après l'autre (meilleures perfs), de mieux profiter des lignes de cache des processeurs modernes (perfs++++) et de profiter des instructions vectorielles des processeurs (perfs++).

                Personnellement, dans mon travail au jour le jour, ces améliorations auront un impact bien plus faible que si je faisais du calcul numérique.
                Malgré tout, l’écriture de classes immuables pour la concurrence en serait facilitée et les perfs améliorées, même si ce n'est pas le cœur de notre problème.

                Moi ce qui me ferait réellement plaisir en tant que programmeurs ce serait des tuples a la Python pour facilement retourner plusieurs valeurs d'une fonction :)

      • [^] # Re: Fin de la pureté de Java

        Posté par  . Évalué à 4.

        on n'est plus à deux exceptions près. ;)

        tu penses comme moi à NullPointerException et OutOfMemoryException ?

  • # Autre JEP

    Posté par  . Évalué à 8.

    Ca intéressait des gens des journaux sur les autres JEP, JDK enhancement proposal, d'OpenJDK 8 ? C'est en général beaucoup plus bas niveau que la syntaxe du langage et API. Ca n'intéresse donc absolument pas les "développeurs struts" mais plutôt les curieux et ceux qui font du code bas niveau (ca permet sûrement aussi au dev C++ de rigoler en disant que ça fait 20 ans qu'ils peuvent gérer ces problèmes de 33 façons différentes mais personne n'est d'accord sur laquelle).

    • [^] # Re: Autre JEP

      Posté par  . Évalué à 5.

      Yep!

    • [^] # Re: Autre JEP

      Posté par  . Évalué à 5.

      Je pense que ça intéresserait des gens, il suffit de voir tout ceux qui se plaignent qu'on ne parle pas assez de technique.

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

Suivre le flux des commentaires

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