Points Clés
- Depuis Java 8, un certain nombre de nouvelles fonctionnalités utiles dans le langage ont été introduites, ainsi que de nouveaux outils et des améliorations de la performance, en particulier dans le ramasse-miettes.
- Lorsque vous choisissez de mettre à niveau, le choix auquel vous êtes confronté est de savoir s'il faut mettre à niveau vers la dernière version de Java (12) et être prêt à mettre à niveau tous les six mois ; ou mettre à niveau vers la dernière LTS (11) pour vous donner jusqu'à trois ans pour penser à votre prochaine mise à niveau.
- Ne soyez pas tenté d'ignorer les avertissements du compilateur. La dépréciation est prise beaucoup plus au sérieux dans les versions récentes de Java, et des API de Java 10 et Java 11 ont été supprimées.
- L'un des changements par rapport à Java 9 était que les API internes (principalement les classes dans les packages qui commençaient avec sun.misc.*) étaient cachées de l'utilisation. Les API qui ne sont pas au cœur du JDK ont également été supprimées dans Java 11. Ces changements peuvent avoir une incidence sur votre application, mais il existe une façon claire d'éviter ces problèmes.
- Une fois "passée le cap" de cette première mise à jour, cela vaut la peine de tester l'application sur la dernière version de Java tous les 6 mois, par exemple dans une chaîne d'Intégration Continue.
Les entreprises ont traditionnellement été réticentes à mettre à niveau vers la dernière version de Java jusqu'à ce qu'elle ait été pleinement prouvée. Cela devient de plus en plus difficile car nous avons de nouvelles versions de Java tous les six mois depuis la sortie de Java 9 en septembre 2017. Ainsi, même si Java 9 date de moins de deux ans, la dernière version est maintenant Java 12.
Ce rythme de changement peut être intimidant, et une mise à niveau de Java 8, comme la majorité des applications l'utilisent à l'exécution, vers Java 12 peut sembler être une grosse charge de travail. Dans cet article, nous allons examiner :
- Les avantages de la mise à niveau
- Les problèmes potentiels liés à la mise à niveau
- Quelques conseils pour la mise à niveau
Pourquoi mettre à jour ?
Avant d'entrer dans les détails de la mise à niveau, nous devrions examiner sérieusement les raisons pour lesquelles nous le voulons.
Les caractéristiques
En tant que développeurs, nous sommes plus intéressés par les nouvelles fonctionnalités du langage ou des APIs qui viennent à chaque mise à jour du langage. Depuis Java 8, nous avons eu beaucoup de nouvelles fonctionnalités, et aussi de nouveaux outils qui peuvent changer notre façon de travailler. J'ai choisi quelques fonctionnalités clés que des développeurs m'ont dit qu'elles leur ont rendu la vie plus facile lorsqu'ils travaillent avec la dernière version de Java.
L'inférence de type pour les variables locales (var
) est un bel exemple de sucre syntaxique qui aide à réduire le code verbeux et répétitif (boilerplate code). Ce n'est pas une solution universelle à tous les problèmes de lisibilité, mais l'utiliser au bon moment peut aider le lecteur du code à se concentrer sur la logique métier (ce qu'il fait) plutôt que sur du code verbeux et répétitif (boilerplate code) (comment il le fait).
Convenience Factory Methods for Collections facilite considérablement la création de collections telles que des Lists, des Maps et des Sets. Les factory methods proposées créent des collections non modifiables, ce qui les rend plus sûres à utiliser.
Collecting to unmodifiable collections permet de collecter les éléments d'un Stream dans des collections non modifiables (immuable) à l'aide des nouvelles opérations de Collector.
Predicate::not fournit un moyen facile d'inverser la valeur d'un Predicate exprimé sous la forme de lambdas ou de références de méthodes, ce qui réduit encore une fois la complexité de notre code.
Les nouvelles méthodes sur Optional donnent encore plus d'options pour coder dans un style fonctionnel lors de l'utilisation d'un Optional au lieu d'avoir à d'imbriquer maladroitement des if.
JShell est le REPL qui nous permet d'exécuter des lignes de code individuelles, ou même des scripts, en Java. C'est une façon agréable d'expérimenter de nouvelles fonctionnalités, et nous pouvons l'utiliser localement sur nos machines de développement sans avoir à adopter de nouvelles versions de Java dans notre code d'application de production.
Un Client HTTP est intégré au JDK. Presque tout le monde travaille avec HTTP sous une forme ou une autre, via des applications web, des services REST, ou autre. Le client intégré élimine le besoin de dépendances externes et supporte HTTP 1.1 et 2 avec les modèles de programmation synchrones et asynchrones.
Les fichiers Multi Release Jar sont l'un des outils que les développeurs de bibliothèques peuvent utiliser pour répondre aux besoins de ceux qui utilisent les dernières versions de Java ainsi que ceux qui sont obligés d'utiliser des versions antérieures.
JLink est un outil fantastique rendu possible grâce au système de modules de Java (Java Module System) qui nous permet de ne packager et déployer que les éléments du JDK dont nous avons vraiment besoin.
Les performances
D'une manière générale, chaque nouvelle version est plus performante que la précédente. "Plus performant" peut prendre de nombreuses formes, mais dans les versions récentes, nous avons constaté des améliorations au niveau du temps de démarrage, de la réduction de l'utilisation de la mémoire. L'utilisation d'instructions spécifiques du CPU se traduit par un code qui utilise moins de cycles CPU, entre autres choses. Java 9, 10, 11 et 12 s'accompagnent tous de modifications et d'améliorations importantes dans le ramasse-miettes, y compris le changement du ramasse-miettes par défaut qui utilise G1, des améliorations à G1 et trois nouveaux ramasses-miettes expérimentaux (Epsilon et ZGC en Java 11, et Shenandoah en Java 12). Trois d'entre eux peuvent sembler exagérés, mais chaque ramasse-miettes est optimisé pour des cas d'utilisation différents. Vous avez donc maintenant le choix entre des ramasse-miettes modernes, dont l'un peut avoir le profil qui convient le mieux à votre application.
La réduction des coûts
Les améliorations apportées aux versions récentes de Java peuvent entraîner une réduction des coûts. En particulier, des outils comme JLink réduisant la taille de l'artefact que nous déployons, et les récentes améliorations dans l'utilisation de la mémoire pourraient, par exemple, réduire nos coûts de cloud computing.
Il y a toujours un autre avantage potentiel à prendre en compte dans le fait que l'utilisation des versions modernes d'un langage vous permet également d'attirer un éventail plus large de développeurs, car de nombreux développeurs aiment avoir la possibilité d'apprendre de nouvelles choses et d'améliorer leurs compétences. L'utilisation d'une version moderne de Java a un impact sur la rétention et le recrutement des développeurs, ce qui a un impact sur le coût de fonctionnement de votre équipe.
Les préoccupations relatives à la mise à niveau
Beaucoup de choses ont changé depuis Java 8, et pas seulement en termes de fonctionnalités dans le langage. Oracle a commencé à publier deux versions différentes, chacune avec une licence différente (une version commerciale que vous devez payer pour l'utiliser en production et une version OpenJDK open source) et a modifié ses modèles de mises à jour et de support. Cela a créé une certaine confusion dans la communauté, mais en fin de compte, cela nous a donné plus de choix par rapport au JDK que nous utilisons. Nous devons examiner à la fois les options qui s'offrent à nous et ce que nous attendons du JDK.
Quelle version utiliser ?
Il peut sembler qu'il y a un grand choix de versions après Java 8 étant donné que la dernière version est Java 12. En fait, le choix est un peu plus simple. Maintenant nous avons des versions tous les six mois, chaque nouvelle version remplace la précédente. L'exception est que tous les trois ans, il y a une version dîte Long Time Support (LTS). Cela permet aux entreprises de choisir un cheminement de mise à niveau avec lequel elles sont à l'aise - soit une mise à niveau au plus tard tous les six mois, soit une mise à niveau de style traditionnel tous les trois ans vers la prochaine version LTS. Java 8 était une LTS, bien qu'Oracle ait cessé de fournir des mises à jour de Java 8 (gratuites) en janvier de cette année. Java 11 est l'actuelle LTS, et bien qu'Oracle ne fournisse pas de mises à jour gratuites maintenant que Java 12 est sorti, il existe de nombreuses versions du JDK en provenance d'organisations qui fourniront des mises à jour pour au moins trois ans.
Le choix qui s'offre à vous est le suivant : passer à la dernière version de Java (12) et être prêt à mettre à niveau tous les six mois ; ou passer à la dernière LTS (11) pour vous donner jusqu'à trois ans pour penser à votre prochaine mise à niveau. Anecdotiquement, nous nous attendrions à ce que les grandes organisations passent d'une version de LTS à l'autre, tandis que les start-ups pourraient bien se mettre à jour tous les six mois. L'avantage de la cadence de publication plus rapide et prévisible, c'est qu'elle prend en charge les deux options.
Quel build utiliser ?
Ce n'est pas parce qu'Oracle ne fournit pas de mises à jour gratuites de ses versions LTS qu'il n'est pas possible d'exécuter une LTS en production et d'obtenir des mises à jour gratuites. Il y a beaucoup d'autres organisations et fournisseurs qui proposent des versions d'OpenJDK (l'implémentation de référence du JDK sur laquelle même le JDK commercial Oracle est basé). Plutôt que de les énumérer tous ici, n'hésitez pas à consulter cette liste qui couvre les fournisseurs de builds OpenJDK gratuits, les dates auxquelles les mises à jour publiques gratuites seront disponibles et les détails du support commercial.
Cela peut sembler plus compliqué qu'avant. Il y a d'autres facteurs à considérer, c'est vrai, mais c'est l'effet d'avoir plus de choix. Les Java Champions ont préparé une discussion beaucoup plus complète sur le sujet des licences, du support, des mises à jour et des différentes options qui s'offrent à nous, et il y a aussi une session de questions/réponses de QCon London 2019 sur ce sujet.
Java 9 n'a-t-il pas tout cassé ?
La principale préoccupation que de nombreux développeurs ont en pensant à la mise à niveau de Java 8 sont les grands changements qui sont venus dans Java 9 et la crainte que ces changements puissent casser les applications. L'un des changements a été l'encapsulation des API internes, ce qui signifie que certaines méthodes qui étaient auparavant disponibles dans le JDK ne sont plus accessibles. Ceci, ainsi que la suppression de tools.jar et rt.jar semblaient alarmants au moment de la sortie de Java 9, mais avec le recul, cela semble avoir été plus un problème pour les développeurs de bibliothèques, de frameworks et de langages que pour les développeurs d'applications.
Si votre application ne fait pas de chose qu'elle ne devrait pas faire (comme utiliser des API internes ou des méthodes obsolètes), migrer vers Java 9 ou au-delà n'est pas aussi effrayant qu'il peut paraître. Bon nombre des problèmes auxquels la communauté a été confrontée ont en fait été traités dans les outils de compilation et les bibliothèques que nous utilisons.
Des conseils pour la mise à niveau
Chaque processus de mise à niveau sera spécifique à l'application migrée. Cependant, il existe quelques bonnes pratiques de base qui faciliteront le processus. Celles-ci sont décrites dans l'ordre dans lequel vous devez les aborder, et vous verrez que que pour les premières étapes, vous n'avez même pas besoin d'utiliser un JDK mis à jour.
Ne pas ignorer les avertissements du compilateur
Les avertissements sont là pour une raison, et si vous les lisez, ils parlent souvent de fonctionnalités qui pourraient disparaître à l'avenir. Si vous travaillez avec Java 8, sur un JDK 8, et que vous voyez des avertissements d'obsolescence ou des avertissements de fonctionnalités que vous ne devriez pas utiliser (voir Figure 1), corrigez ces avertissements avant d'essayer de passer à un JDK plus récent.
Figure 1 - Exemples d'avertissements du compilateur provenant du JDK 8
Notez que la dépréciation est prise beaucoup plus au sérieux dans les versions récentes de Java, et que Java 10 et Java 11 ont supprimé des API.
La vérification de l'utilisation des API internes
Un des changements introduit dans Java 9 était que les API internes (principalement les classes dans les packages qui commençaient avec sun.misc.*
) étaient cachées de l'utilisation.
Il y a un outil, jdeps, qui fait partie du JDK que vous pouvez exécuter avec l'option -jdkinternals
pour vérifier si un ensemble de classes utilise quelque chose qu'il ne devrait pas. Par exemple, si j'exécute la commande suivante dans le répertoire de sortie de mon projet :
> $JAVA_HOME\bin\jdeps -jdkinternals .
J'obtiens alors la sortie suivante :
. -> /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre/lib/rt.jar
com.mechanitis.demo.sense.twitter.connector.TwitterOAuth (.)
-> sun.misc.BASE64Encoder JDK internal API (rt.jar)
-> sun.misc.Unsafe JDK internal API (rt.jar)
Warning: JDK internal APIs are unsupported and private to JDK implementation that are subject to be removed or changed incompatibly and could break your application.
Please modify your code to eliminate dependency on any JDK internal APIs. For the most recent update on JDK internal API replacements, please check: https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool
JDK Internal API Suggested Replacement
---------------- ---------------------
sun.misc.BASE64Encoder Use java.util.Base64 @since 1.8
sun.misc.Unsafe See http://openjdk.java.net/jeps/260
Cet outil n'identifie pas seulement les classes qui utilisent les API internes, mais fournit également une suggestion sur ce qu'il faut utiliser en remplacement.
Mettez à jour votre outil de build
Si vous utilisez Maven ou Gradle, vous devez effectuer une mise à niveau.
Gradle
Gradle 5.0 a introduit le support de Java 11, nous devrions donc utiliser au moins la version 5.0. La version actuelle est la 5.3.1 et a été publiée le mois dernier.
Maven
Nous devons utiliser au moins la version 3.5.0 (la version actuelle est 3.6.0), et nous devons nous assurer que le plugin du compilateur Maven est au moins la version 3.8 :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release> <!-- or 12 -->
</configuration>
</plugin>
Mettez à jour vos dépendances
Certains des problèmes dont vous avez peut-être entendu parler concernant la migration vers Java 9 ou une version ultérieure sont des problèmes rencontrés (et potentiellement corrigés) par les bibliothèques et frameworks. Par exemple, de nombreux frameworks utilisent la réflexion et des API internes en sous-jacents. Pour que votre application ait les meilleures chances de continuer à fonctionner correctement, vous devez vous assurer que toutes vos dépendances sont à jour. De nombreuses bibliothèques ont déjà été mises à jour pour fonctionner avec Java 9 et au-delà, et il y a un effort continu de la communauté pour assurer que cela continue.
Certaines dépendances devront peut-être être remplacées. Un certain nombre de bibliothèques ont migré vers Byte Buddy pour la génération de code et les proxies, par exemple, car il fonctionne bien avec toutes les versions récentes de Java. Lorsque vous examinez une migration vers Java 11, vous devez avoir une bonne compréhension de vos dépendances et savoir si elles ont été mises à jour pour prendre en charge les versions de Java postérieures à 8.
Ajouter des dépendances pour les fonctionnalités qui ont été retirées
Les API qui ne sont pas au cœur du JDK ont été supprimées. Cela inclut les modules Java EE, Corba et JavaFX. C'est généralement simple à corriger, en ajoutant la bonne bibliothèque à votre gestion des dépendances. Par exemple, ajouter une dépendance vers JAXB pour Gradle ou Maven. JavaFX est un cas un peu plus complexe, mais il existe une bonne documentation sur le site OpenJFX.
Exécuter l'application avec le nouveau JDK
Vous n'avez pas besoin de recompiler votre application pour utiliser la dernière version de Java, c'est en partie la raison pour laquelle les développeurs du langage travaillent si dur pour maintenir une compatibilité descendante. Vous pouvez exécuter votre application dans votre environnement d'intégration continue (par exemple) en utilisant un nouveau JDK sans modifier le code.
Compiler avec le nouveau JDK
Nous pourrions encore être en train de compiler nos applications avec Java 8 pour toutes ces étapes précédentes. Ce n'est que lorsque vous aurez fait ces autres étapes que vous devriez envisager de compiler en Java 11 ou 12. Rappelez-vous, nous pouvons compiler notre application avec une version dans une version inférieure si nous ne voulons pas utiliser de nouvelles fonctionnalités, donc nous restons ouverts à revenir à l'ancienne version. Par exemple, avec Maven :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
Ou avec Gradle :
sourceCompatibility = JavaVersion.VERSION_1_8
Commencer à utiliser les nouvelles fonctionnalités
Ce n'est que lorsque tout fonctionnera, que tous vos tests s'exécuteront et que tout aura l'air performant, et peut-être qu'après un certain temps en production, vous pourrez envisager d'utiliser les nouvelles fonctionnalités du langage.
N'oubliez pas non plus que même si la version 9 de Java a introduit le système de modules en Java, les applications n'ont pas besoin de l'utiliser du tout, même si elles ont migré vers une version qui le supporte. Cependant, si vous êtes intéressé à adopter le système de modules, nous avons un tutoriel à ce sujet ici à InfoQ.
En résumé
Beaucoup de choses ont changé depuis Java 8 : nous recevons une nouvelle version tous les 6 mois ; les licences, les mises à jour et le support ont changé ; le fournisseur de notre JDK peut avoir changé. Mais maintenant que Java 11 a remplacé Java 8 en tant que dernière version LTS, et maintenant que les principales bibliothèques, frameworks et outils de build ont adopté les dernières versions de Java, c'est le bon moment pour migrer votre application vers Java 11 ou 12.
Après avoir passé le cap de cette première mise à jour, cela vaut au moins la peine de tester l'application sur la dernière version de Java tous les 6 mois, par exemple dans une intégration continue (CI). Dans un monde idéal, vous pourriez même être en mesure de monter dans ce train de release de six mois, en utilisant la prochaine version de Java tous les 6 mois et en étant capable d'utiliser les nouvelles fonctionnalités dès qu'elles sont disponibles.
À propos de l'auteur
Trisha Gee est une Java Champion et a développé des applications Java pour une gamme d'industries, y compris la finance, la fabrication, les logiciels et les organismes sans but lucratif, pour des entreprises de toutes tailles. Elle possède une expertise dans les systèmes Java haute performance, est passionnée par la productivité des développeurs et s'intéresse de près au développement open source. Elle est Developer advocate Java pour JetBrains, qui est l'excuse parfaite pour vivre à la pointe de la technologie Java.