Alors que Java vient de fêter ses 20 ans, Java 8 a soufflé il y a peu sa première bougie. J’avais suivi de loin l’évolution de Java 8 lors de son développement sans vraiment chercher à l’utiliser en pratique. Mais le hasard fait bien les choses, et Devoxx France 2014 suivait de près sa sortie. Je me suis dit que c’était l’endroit idéal pour se familiariser avec cette toute nouvelle version. Et je n’ai pas été déçu, j’ai suivi deux universités consacrées à Java 8. La première était proposée par Rémi Forax et expliquait l’histoire des lamba et comment elles ont été implémentées, la suivante était celle de José Paumard qui nous montrait toute la puissance de l’API stream. Ainsi, de retour de Devoxx je n’ai pas mis longtemps à me familiariser avec cette nouvelle version que j’utilise maintenant quotidiennement depuis un an. Il est donc temps pour moi d’en dresser un premier bilan.
Optional
J’utilisais depuis un certain temps le concept d’Optional proposé par Guava, je l’avais d’ailleurs recommandé. Java 8 intègre nativement ce concept avec une API très similaire. L’adaptation à ce nouveau concept de Java 8 a donc été très simple.
Le fait qu’Optional soit supporté nativement par Java 8 rend son utilisation possible par des API ou des bibliothèques dont l’objectif est généralement d’avoir le moins de dépendances possibles. J’espère qu’il va se généraliser.
Programmation fonctionnelle
L’évolution la plus importante de Java 8 est très probablement l’arrivée de la programmation fonctionnelle, notamment grâce au support du concept de lambda.
Java proposait jusqu’à présent un modèle orienté objet assez complet, mais il montrait clairement ses limites dans certaines situations qui arrivaient malgré tout assez souvent. C’est typiquement le cas quand on veut définir une fonction, quelle que soit son utilité. C’était possible, il fallait définir une interface avec une méthode qui décrit le comportement de la fonction. Nous avions alors la possibilité de créer une classe autonome qui implémente la fonction, mais quand l’implémentation n’a du sens que dans un cas d’utilisation, c’est un peu lourd de créer une classe seulement pour cela. C’est la raison pour laquelle nous écrivions souvent des classes anonymes qui permettent de définir la fonction là où on en a besoin et d’accéder à des variables du contexte sans avoir d’autre chose à faire que des les mettre en final.
Cette technique a fait ses preuves pendant de longues années, mais elle est très lourde et verbeuse. Elle ne favorise pas la lisibilité du code. Les lambda de Java 8 apportent une solution à ce problème, en alliant élégance et efficacité. Elles viennent compléter le modèle objet de Java avec une touche de programmation fonctionnelle, ce qui est d’ailleurs le cas dans la plupart des langages modernes, Java étant jusqu’à présent clairement à la traîne.
Les lambda de Java 8 représentent une évolution très appréciable que j’utilise assez fréquemment. Après coup, je constate que certains usages que j’ai pu en faire sont très probablement excessifs. Et oui, quand on y prend goût on a vite tendance à vouloir en mettre de partout, d’autant plus que la plupart des API que nous utilisons sont maintenant bien compatibles avec la programmation fonctionnelle. Et justement, la programmation fonctionnelle est à mon idée à utiliser avec parcimonie.
La syntaxe des lambda est assez nouvelle. Bien qu’elle soit relativement intuitive, elle est difficile à comprendre par des développeurs qui ne sont pas familiers avec le concept de programmation fonctionnelle, et ils sont encore nombreux à ne pas avoir franchi le pas.
Des abus de programmation fonctionnelle peuvent également être nuisibles à la lisibilité du code, et ce même pour des développeurs familiers avec ces concepts. J’ai bataillé à plusieurs reprises pour essayer de comprendre un code que j’avais moi-même écrit. Cela faisait longtemps que ça ne m’était pas arrivé.
La programmation fonctionnelle permet d’exprimer beaucoup de choses en peu de caractères. C’est appréciable, mais cela conduit à du code très dense, dans lequel chaque caractère a son importance, comme nous le montre cette parfaite illustration écrite en Scala. De plus, cela remet en cause le principe de continuité du code dont nous avons l’habitude quand nous le lisons en introduisant une forme d’asynchronisme. Une lambda n’est en effet pas exécutée au moment où elle est définie, elle est peut-être même exécutée plusieurs fois ou dans une temporalité toute autre que le code dans lequel est est référencée.
Il m’arrive parfois de remplacer une ligne dense de programmation fonctionnelle par quelques lignes plus classiques parce que je me rends compte que la lisibilité est trop altérée. Quand j’utilise l’API stream de Java 8, il m’arrive de devoir enchaîner plusieurs lambda ou method references à la suite. Je me fixe une règle : pas plus d’une action par ligne, de façon à visualiser clairement les différentes étapes.
Streams
L’arrivée de la programmation fonctionnelle dans Java 8 a été exploitée à de nombreux endroits dans le JDK, et c’est particulièrement le cas avec la toute nouvelle API stream.
Elle permet de remplacer une manipulation de collections qui aurait pris 100 lignes avant en quelques lignes seulement. Elle n’est pas forcément très simple à prendre en main parce qu’elle est basée sur la notion de streams qu’il est nécessaire de comprendre (José Paumard l’explique si bien), mais une fois qu’on l’a prise en main, son efficacité est redoutable dès lors qu’il s’agit d’appliquer des opérations sur un ensemble de valeurs, que ce soit du filtrage, de la transformation ou du groupage, des choses qui jusqu’à présent prenaient de nombreuses lignes avec la boucle foreach.
Par contre à plusieurs reprises j’ai abandonné après avoir essayé de faire des choses plus avancées avec cette API, notamment en utilisant groupingBy. Il faut avoir les idées bien claires et du temps devant soi pour s’en sortir. J’ai du coup des doutes quant au fait que le code soit lisible à la fin, même si l’écriture est bien plus compacte. Cela m’a rappelé les exemples avancés que proposait José Paumard lors de son université Java 8 à Devoxx 2014.
Migration
Certains morceaux de code qui tournaient parfaitement avec Java 7 ne fonctionnent plus avec Java 8. Les changements sont détaillés ici. Le point dont j’ai le plus entendu parler est celui qui concerne Class.getMethod.
De mon côté, la migration du produit sur lequel je travaille (basé sur Play Framework) n’a posé aucun problème. Je suppose que la plupart des bibliothèques ou frameworks ont anticipé en amont les changements liés à Java 8 et les ont ainsi éliminés pour la plupart avant même sa sortie officielle.
Production
Notre code est en production en Java 8 depuis pratiquement un an et nous n’avons eu aucun indicent dû à Java 8. A ce niveau-là le passage de Java 7 à Java 8 a été totalement transparent.
En revanche, Java 8 n’est pas encore vraiment intégré dans les distributions Linux. Il n’est pas disponible dans la version stable actuelle de Debian (Wheezy), il ne le sera malheureusement pas non plus dans la prochaine version (Jessie). Ubuntu propose OpenJDK 8 dans Utopic (14.10) mais pas dans la dernière LTS (Long Term Support) qu’est Trusty (14.04). Côté Red Hat, je crois qu’il en est plus ou moins de même. Vu la lenteur des cycles de version des distributions les plus utilisées en production, ce problème n’est malheureusement pas près de se résoudre.
Conclusion
La version 8 de Java a littéralement donné un coup de jeune au langage et je pense qu’elle va être très populaire. En tout cas, moi j’adore. Elle redonne de sérieux arguments à Java qui était en train de perdre de sa popularité.
Je me demande par contre combien de temps les entreprises vont mettre à l’adopter. Quand on voit qu’aujourd’hui de nombreuses entreprises en sont encore à Java 6 ou même 5, je me dis que beaucoup de développeurs ne pourront pas en profiter pendant encore quelques années.
En tout cas, cette fois plus que d’habitude, passer à la version supérieure de Java apporte réellement beaucoup de valeur. Je conseille néanmoins de s’assurer que les développeurs aient un minimum de connaissances à propos des nouveautés et surtout au sujet de la programmation fonctionnelle pour qu’ils ne soient pas perdus et puissent en exploiter la puissance.
L’image d’en-tête provient de Flickr.
nous sommes en pleine réflexion sur la direction à donner aux futurs développements:
– conserver le langage JAVA et la JVM,
– dans l’affirmative, est-ce qu’il est venu le moment de passer à la version 8.
Merci pour votre retour d’expérience sur l’utilisation de JAVA 8 qui répond parfaitement à nos 2 interrogations
Bonjour.
Je suis content que mon retour d’expérience sur Java 8 ait pu vous rendre service.
Benoit.
Bonjour Benoît,
Sympa ton article, ça montre le bon exemple.
Mais même aujourd’hui à l’arrivée prochaine de Java 9, le Java 8 n’est pas près de vraiment être utilisé, quand on vois que Java FX et toujours très peu utilisé or que c’est tellement plus puissant que Swing.
Merci encore pour ton article et à bientôt,
– Sébastien
Bonjour Sébastien et merci pour ton commentaire.
Dans mon entourage, tout le monde est passé à Java 8, mais ce sont des développeurs passionnés pour la plupart. Je ne sais pas ce qu’il en est dans des boîtes moins technologiques ou dans des grosses boîtes qui ont des règles strictes et qui n’ont pas encore fait évoluer ces règles pour passer à Java 8.
Quoi qu’il en soit, il est temps de s’y mettre. Oracle a invité il y a deux ans les utilisateurs de Java à passer à la version 8 et a même arrêté le support gratuit de Java 7.
Avec maintenant plusieurs années de recul, je confirme que Java 8 apporte énormément de valeur par rapport à Java 7. Cela veut dire notamment une bien plus grande productivité. Soyons professionnels, utilisons les outils de notre temps et pas ceux du temps ancien !
Bonne journée !