Il ne t’aura pas échappé, cher lecteur, qu’après l’année 2012 (année de la loose), ce sera au tour de l’année 2013, que tous les Javaistes distingués appellent déjà « année de la braise ». La braise en deux temps : le premier à Pâques avec la sortie de JEE 7, et le second en ce moment, puisque java 8 atteint aujourd’hui même le stade « developper release ». Les mauvaises langues le disent déjà : une fois retardé, Java 8 sera à l’heure, la question porte sur son contenu. On sait depuis un moment que Jigsaw n’en sera pas, quelles autres API ont été sacrifiées sur l’autel de ponctualité ?
Et la developer release fut !
Qui vivra verra, on le savait déjà, mais pour Java, on voit déjà, puisque c’est en fait en juillet que Java 8 a atteint l’état FC. Et non, FC ne signifie pas « finally cramed », ni même « fundamentally crippled », mais bien « feature complete », ce qui, en bon français, signifie à peu près que tout est la. En gros, ça veut dire que depuis juillet, on sait ce qui est et ce qui n’est pas dans Java 8, et donc par ricochet dans Java 9, voire les suivants. Et aujourd’hui même sort la version DR, « developper release ». Acère tes canines, ami développeur, tu vas pouvoir te jeter sur un beau morceau de chair fraîche. En mars, nous aurons la version finale, elle sera dehors malgré le froid, estampillée du magique V8, qui sent bon la performance, et pas seulement dans l’univers Java.
Et qu’aura-t-on donc dans cette version ? Un seul mot efface tout le reste : les lambdas. Heureusement le support d’UTF-8 a été mis à jour en Java 7, il fallait bien ça pour avoir des lambdas corrects, bien affichés, qui ne se transforment pas en odieux @&e au hasard des navigateurs et autres éditeurs de texte un peu anciens.
Mais non, cher lecteur, ça n’est pas d’affichage de caractères exotiques qu’il s’agit, mais bel et bien de ces fonctions lambdas, parfois appelées closures, dont le support tant attendu arrive enfin.
L’arrivée des lambdas dans le langage Java est une révolution. Joe Darcy nous l’a dit lors de Devoxx 2012 : l’impact sur le langage et ses API est plus important que l’arrivée des génériques. C’est une bonne partie du JDK qui est réécrite, et en premier lieu le framework Collection, présent depuis Java 2, et dont la conception, fruit du travail de Josh Bloch et Neal Gafter, a maintenant près de 15 ans.
Et ainsi arrivèrent les λ
Cette modification ferait bien de nous apporter quelque chose, car son coût, lui est réel ! L’apport est à deux niveaux.
Le premier, le plus visible : modifier la syntaxe d’écriture des classes anonymes qui n’ont qu’une seule méthode. Et c’est qu’elles sont nombreuses les bougresses : on peut citer rapidement Runnable, FileFilter (et sa copine FilenameFilter), et de nombreuses classes de Swing. Les esprits bien malins risquent de s’arrêter la : j’entends d’ici les chantres du plus-cest-court-plus-cest-bon, du code-concis-donc-lisible-donc-maintenable se réjouir. Car c’est bien connu : la clarté d’une explication se mesure au nombre de mots utilisés : moins y en a, plus c’est clair !
Le second, et à mon avis le plus important : changer complètement la procédure d’appel du code de ces classes anonymes. Une classe anonyme est, comme son nom l’indique, une classe qui doit être instanciée. Une lambda expression ne l’est pas, il s’agit d’un morceau de code, qui pourra être inliné dans le code appelant par le mécanisme d’invokedynamics, sans passer par l’instanciation d’un objet particulier. Gains en performances attendus, dans tous les compartiments de la JVM, allègement du travail du GC, en un mot : le pied.
Et c’est là qu’arrive le célèbre trio map filter reduce, et son introduction dans le framework collection. De quoi s’agit-il ? De trois fonctionnalités applicables sur les tableaux ou collections d’objets.
Map, filter, reduce
L’opération map consiste encore à prendre une collection, et à appliquer une transformation à chacun de ses éléments. Cette transformation prend un objet, et retourne autre chose, a priori d’un autre type. Le résultat est donc une collection, d’un type différent de celui de la collection originelle, et comportant le même nombre d’éléments.
L’opération filter consiste à prendre une collection, et à appliquer une fonction booléenne à chaque élément de cette collection. Le résultat est une collection, qui ne comporte que les objets qui ont passé le test, c’est-à-dire pour lesquels l’application de cette fonction a retourné true. Un filtrage retourne donc une collection dont le type est le même que celui de la collection originelle, mais comportant a priori moins d’éléments.
L’opération reduce consiste enfin à prendre une collection, et à accumuler les éléments de cette collection à l’aide d’une fonction associative. Le résultat est donc un objet unique, d’un type qui peut être différent, même si, en principe, il devrait être le même. Faire la somme des nombres d’une collection, ou en calculer le maximum, ou encore la moyenne, sont autant de réductions.
Ces trois opérations sont particulièrement pratique à traiter avec des lambdas. On passe l’expression à la collection, qui se débrouille pour se l’appliquer à elle-même et le tour est joué. Facile à écrire, facile à lire, facile à comprendre. Facile aussi à optimiser, puisque c’est l’API qui le fait.
Collections et λ
Pourquoi les lambdas constituent-ils une révolution dans notre univers de développeur ? Parce que pour la première fois depuis 15 ans, les patterns de traitement des collections vont changer dans le JDK. L’API Collection est universellement utilisée. Même si elle n’est pas si bien connue que cela (à mon avis), je ne connais aucun projet qui ne l’utilise pas. Même les plus grands chantres du NDH (not developped here) reculent devant la réécriture d’ArrayList. L’API Collection avait déjà été réécrite lors de la sortie de Java 5, mais la façon dont on l’utilisait n’avait pas changé.
Changer les patterns de l’API Collection signifie simplement changer la façon dont on écrit les codes des traitements métier, changer la façon dont on organise ces traitements, et donc changer la façon dont on les conçoit. En un mot : changer fondamentalement nos habitudes de travail.
Et pourquoi cela ? Après tout, pourquoi changer des méthodes qui ont fait leurs preuves, et ce depuis 15 ans ? Pour une raison très simple : ces nouveaux patterns permettent de déporter les traitements d’optimisation dans l’API, à commencer par la parallélisation. Ces nouveaux patterns vont nous permettre d’écrire des traitements parallèles quasi gratuitement. Inutile de programmer le tri d’un tableau avec un fork / join : l’API le propose sur étagère.
Ne loupe pas cette étape, cher et précieux lecteur, car derrière le virage arrive une côte digne de l’Alpe d’Huez. Certains sauront la monter, d’autres auront du mal. Mais la génération suivante elle, partira directement du haut.
Références
Calendrier de sortie de Java 8 : http://openjdk.java.net/projects/jdk8/milestones
La page de téléchargement : http://jdk8.java.net/download.html