Points Clés
- Le langage Java a considérablement changé au cours des 5 dernières années
- Deux grands projets qui apportent ce changement - Valhalla et Amber - sont toujours en cours
- Java a continué de maintenir sa valeur fondamentale de compatibilité descendante
- Malgré ses 25 ans, il reste encore beaucoup de vigueur dans le langage et la plateforme
- De nouvelles technologies, telles que Graal, contribuent à maintenir Java à la pointe des langages de programmation
Il y a près de cinq ans, j'ai écrit un article décrivant quelques idées de fonctionnalités d'autres langues que je ressentais comme pouvant être bénéfique pour Java. Beaucoup de choses se sont passées depuis lors - à cette époque, Java 8 était la nouvelle version, alors que la version la plus récente est maintenant Java 14.
Examinons tour à tour chaque fonctionnalité et voyons quel est son état actuel : si elle a été ajoutée à Java, est en cours de réalisation ou n'est pas actuellement prévue pour inclusion.
Génériques réifiés
Mes prédictions originales excluaient les génériques réifiés. Je n'avais pas prévu l'ambition du projet Valhalla de refondre la JVM de fond en comble.
Les principaux objectifs du projet Valhalla sont les suivants :
- aligner le comportement de la disposition de la mémoire JVM sur le modèle du matériel moderne;
- étendre les génériques pour permettre l'abstraction sur tous les types, y compris les primitives, les valeurs et même void; et
- permettre aux bibliothèques existantes, en particulier le JDK, d'évoluer de manière compatible pour tirer pleinement parti de ces fonctionnalités.
Enterré dans cette description est le mot "valeurs", qui a évolué vers la fonctionnalité que nous connaissons aujourd'hui en tant que classes inline.
Les génériques réifiés et la spécialisation primitive ont ainsi été intégrés dans un projet beaucoup plus vaste qui promet de changer fondamentalement la façon dont Java est écrit et exécuté.
Malgré les profonds changements de bas niveau qui sont effectués, l'équipe de projet a pour objectif de minimiser les perturbations des applications Java existantes et de fournir une approche opt-in facile aux développeurs qui utilisent les capacités de Valhalla dans leur propre code.
Nous devons noter que Valhalla est toujours un travail en cours - et il n'y a toujours pas de feuille de route officielle pour le moment où il pourrait être livré.
Verdict : EN COURS (dans le cadre du projet Valhalla)
Arithmétique non signée
La possibilité de prendre en charge cette fonctionnalité a été discutée à plusieurs reprises au cours de l'histoire de Java, mais son introduction présente un certain nombre de complexités.
Par exemple, il y a la question de savoir comment le non signé doit être représentée dans le système de type Java et si elle doit être visible au niveau du bytecode JVM ou non.
Ces problèmes n'ont pas atteint un consensus satisfaisant et donc Java ne contient toujours pas d'arithmétique non signée - et un aspect notable du projet Valhalla est qu'il n'inclut pas la prise en charge de l'arithmétique non signée.
Verdict : N'EST PAS PRIS EN CONSIDÉRATION
Index longs pour les tableaux
Les tableaux en Java sont limités en taille par un simple fait de leur conception : ils prennent un int comme index. Cela signifie qu'un tableau est limité à 2 ** 31 éléments (en se souvenant que les entiers sont signés), soit environ 2 milliards d'entrées.
Comme envisagé à l'origine, l'idée d'utiliser un long au lieu d'un int permettrait aux développeurs de créer et de manipuler des tableaux beaucoup plus grands. Cependant, depuis l'article original "Fonctionnalités manquantes", l'attention de la communauté dans ce domaine s'est déplacée vers un accès facile aux grandes baies stockées hors du tas (off-heap).
Il y a plusieurs raisons à cela - la facilité d'interopérabilité avec les bibliothèques non Java (y compris le machine learning et d'autres applications lourdes) est l'une des plus importantes. Cependant, il y a aussi des questions sur l'utilité des grands tableaux sur le tas. Les énormes tableaux multi-giga auraient des coûts de copie importants lors de l'entrée et de la sortie du tas Java et pourraient potentiellement causer de sérieux maux de tête au garbage collector de la JVM.
Pour ces raisons, les grands tableaux sont principalement pensés dans le contexte de la prise en charge off-heap, et le concept a été intégré dans les fonctionnalités en cours de développement actif dans le projet Panama.
Verdict : EN COURS (dans le cadre du Projet Panama)
Syntaxe d'importation plus expressive
Aucune tentative sérieuse n'a été faite pour étendre la portée de la syntaxe d'importation ou pour introduire l'alias de type, même au niveau local (ou à portée de fichiers).
Verdict : N'EST PAS PRIS EN CONSIDÉRATION
Littéraux pour les collections
Des méthodes statiques sur les interfaces ont été ajoutées dans Java 9 et les collections ont été mises à jour pour inclure des fabriques pour les collections. Ceux-ci jouent le rôle de littéraux pour les collections en Java :
var ls = List.of(1,2,3);
Comme les fabriques jouent le rôle de littéraux, ce changement a également introduit de nouvelles implémentations des interfaces de collection. Ces implémentations sont immuables, car réutiliser les collections mutables existantes (telles que ArrayList) aurait violé l'attente du programmeur selon laquelle ces valeurs devraient se comporter comme si elles étaient littérales.
Des solutions plus intrusives, telles que l'introduction directe de nouveaux littéraux dans la syntaxe du langage, n'ont pas été recherchées.
Verdict: LIVRÉ (en tant que fabriques)
Types de données algébriques
Les types de données algébriques en Java sont en cours de livraison. La fonctionnalité consiste en deux ajouts majeurs au système de types : les records et les sealed type mais aussi le pattern matching, un nouveau morceau substantiel de la syntaxe.
Java 14 fournit une version preview de deux de ces aspects - en particulier, records, qui en Java sont essentiellement appelés tuples et les composants initiaux du pattern matching.
Les nouvelles caractéristiques qui constituent les premières pièces du pattern matching sont la première forme de pattern en Java : le instanceof pattern et une version standardisée des switch expressions.
Le second est l'échafaudage qui permettra à terme d'introduire le pattern matching, de manière similaire aux expressions de correspondance avec lesquelles les programmeurs Scala peuvent être familiers.
Il y a encore beaucoup d'autres étapes à franchir avant que cette fonctionnalité ne soit pleinement opérationnelle - les records et les patterns ne sont encore qu'en preview. D'autres JEPs, dont la JEP 375, qui élargit le pattern matching d'instanceof pour permettre la déconstruction des records, sont nécessaires pour étoffer le pattern matching dans son ensemble.
À l'arrivée de Java 14, les JPEs clés - y compris les JEP 375 et JEP 360, qui introduit des types scellés [sealed types] - ne sont pas ciblés pour une version spécifique de Java.
Malgré cette absence de feuille de route concrète, il est probable que l'ensemble des types de données algébriques et le mécanisme de pattern matching pourraient être livrés sous une forme normalisée à temps pour la prochaine version du LTS, qui sera Java 17 en septembre 2021.
Verdict : EN COURS (dans le cadre du Projet Amber)
Typage structurel
Le système de types de Java a quelque peu évolué depuis Java 8, mais en pratique, il n'y a pas eu de mouvement significatif vers le typage structurel général. Par exemple, lors de la conception des records, le typage structurel a été explicitement rejeté en faveur de la création de types nominaux.
Cela renforce l'idée que le nom que nous donnons à un type a du pouvoir et de l'importance et que les records de Java sont définis par plus que le nombre et les types de leurs composants.
Un endroit mineur où quelque chose qui ressemble au typage structurel continue d'être vaguement visible en Java est dans les types non dénotables de Java. Ce ne sont vraiment qu'une extension de l'exemple abordé à l'origine dans l'article de 2015 .
Dans cet exemple, nous construisons quelque chose qui ressemble à un type structurel (Objet + <une méthode>) mais ne pouvons l'utiliser que dans une seule expression car il n'y a pas de type dénotable que nous pouvons utiliser comme type de variable pour y affecter la valeur.
Depuis Java 10, le langage a une forme étendue d'inférence de type qui utilise var pour réduire le code boilerplate dans les affectations. Nous pouvons utiliser cette capacité pour étendre la portée dans laquelle nous pouvons appeler des méthodes supplémentaires définies sur un type de cette manière. Cependant, cela est limité à la méthode dans laquelle l'inférence de type se produit. Le type spécial que var infère ne peut pas être propagé au-delà des limites de la méthode précisément parce qu'il n'est pas dénotable.
En réalité, ces cas particuliers ne sont pas de véritables typages structurels et il n'est pas prévu de les introduire. L'attraction gravitationnelle de la conception de Java sur les noms et la typographie nominale est tout simplement trop forte.
Verdict: CONSIDÉRÉ MAIS REJETÉ
Appels dynamiques
Les cinq dernières années ont vu une large expansion de l'utilisation d'invokeddynamic, mais uniquement au sein du JDK et d'un petit nombre de bibliothèques externes techniquement sophistiquées.
Il est toujours vrai que "le langage Java n'a pas de mot-clé ou autre construction pour créer des appels invokedynamic à usage général", tout comme l'article d'origine le disait.
La suggestion que la bibliothèque Dynalink pourrait être étendue pour assumer ce rôle ne s'est jamais concrétisée, et, en fait, l'implémentation Nashorn Javascript qui a produit Dynalink est maintenant elle-même considérée comme obsolète et pourrait être omise de Java 15 (bien que Dynalink lui-même restera).
Les bibliothèques qui utilisent des dynamic call sites le font via l'API MethodHandles qui, bien que légèrement plus facile à utiliser en 2020, est toujours hors de portée de la plupart des programmeurs Java.
La difficulté de trouver un équilibre entre l'invocation dynamique flexible qui ne cause pas trop de problèmes d'exécution et l'utilisation convaincante au niveau de la langue s'est avérée trop grande, du moins pour le moment.
Verdict : N'EST PAS PRIS EN CONSIDÉRATION
Qu'est-ce que j'ai raté ?
Les 5 dernières années ont également vu l'émergence d'un certain nombre de projets et de tendances que je n'avais pas prévus ni abordés dans l'article original. Les plus importants d'entre eux sont peut-être :
- Étendue et portée du projet Valhalla
- Project Amber
- Nouveau modèle de release pour Java
- Graal et GraalVM
- L'émergence de Kotlin
En voici quelques exemples :
Bien que le projet Valhalla ait été lancé en 2014, il a pris de l'ampleur et s'est considérablement développé au cours des années suivantes. C'est devenu le changement le plus ambitieux et le plus important que Java ait jamais vu. Valhalla promet de modifier tous les aspects de la plate-forme Java - de la façon dont la mémoire et les valeurs sont représentées au sein de la machine virtuelle, en passant par le système de type et les génériques, et jusqu'au niveau de la bibliothèque et de la syntaxe du langage.
Ce projet vise à aligner Java avec l'état actuel et futur du matériel et à offrir des performances et d'autres améliorations qui ne peuvent tout simplement pas être traitées au coup par coup. Au lieu de cela, Valhalla vise à déplacer l'état de la plate-forme Java de sa position actuelle (que nous pouvons considérer comme un maxima local) à un endroit qui est beaucoup mieux adapté pour être la base d'une plate-forme pour les décennies à venir.
Les recherches originales sont toujours difficiles à prévoir, et il n'est donc pas surprenant que la montée de Graal m'ait également pris par surprise. L'idée de base est, comme beaucoup d'autres concepts convaincants, très simple une fois que vous l'avez saisie.
Le compilateur JIT habituel de Java est écrit en code C ++ et s'exécute sur des threads dédiés spéciaux au sein de la JVM. Graal part d'une idée simple : que se passerait-il si, à la place, le compilateur JIT était écrit en Java et que les threads du compilateur exécutaient réellement une deuxième copie de l'interpréteur Java ?
Le compilateur JIT en mode interprété serait aussi capable que le JIT actuel - il pourrait donc compiler n'importe quel fichier de classe en code machine. Nous devrions nous attendre à ce qu'il soit plus lent que le compilateur C ++ existant, mais il ne différerait pas dans son comportement, seulement dans les performances.
Prenant cette idée à sa conclusion logique, cela signifie que le JIT en mode interprété pourrait compiler les fichiers de classe qui composent le JIT lui-même. Une fois qu'il a fini se période de chauffe (warm up), il pourrait se remplacer lui-même et fonctionner avec les mêmes performances que le JIT natif d'origine.
Cette idée intrigante s'avère être le point de départ d'une classe majeure de nouvelles technologies, y compris la compilation native de Java (AOT) ainsi qu'une nouvelle machine virtuelle polyglotte (GraalVM) capable d'exécuter de nombreux langages différents.
Conclusions
La plate-forme Java a gagné en sophistication au cours des cinq dernières années, avec de nombreuses nouvelles fonctionnalités dans le langage et la VM livrées ou en cours de développement. En supposant que les tendances actuelles se poursuivent, la communauté sera probablement plus intéressée par l'ensemble des fonctionnalités standardisées qui seront disponibles dans Java 17 (en septembre 2021).
Ce sera un Java très différent de celui qui existait en 2014 lorsque nous avons fait nos observations originales, et bien que certaines fonctionnalités aient été livrées, il semble clair que certaines autres ne seront probablement jamais livrées et d'autres encore ont été réalisées sous une forme très différente. Nous sommes impatients de voir ce que les cinq prochaines années apporteront au langage et à la plate-forme Java, et en particulier les aspects que nous ne pouvons pas prédire pour le moment.
A propos de l'auteur
Ben Evans est co-fondateur de jClarity, une société d'optimisation des performances de JVM. Il est organisateur du LJC (London's JUG) et membre du comité exécutif du JCP, aidant à définir des normes pour l'écosystème Java. Ben est Java Champion; 3 fois JavaOne Rockstar Speaker; auteur de "The Well-Grounded Java Developer", la nouvelle édition de "Java in a Nutshell" et "Optimizing Java". Il est un conférencier régulier sur la plate-forme Java, les performances, l'architecture, la concurrence, les startups et les sujets connexes. Ben est parfois disponible pour parler, enseigner, écrire et des missions de conseil - vous pouvez le contacter pour plus de détails.