39 nouvelles fonctionnalités disponibles dans Java 12

Extrait d'une merveilleuse interview sur Habré: «Simon Ritter est une personne qui a travaillé sur Java depuis le tout début et continue de le faire en tant que directeur technique adjoint d'Azul, une entreprise travaillant sur la machine virtuelle Jing Zing et l'un des meilleurs ramasseurs de déchets, C4 (Continuously Concurrent Compacting Collectionneur) »
Vous trouverez ci-dessous une traduction de son article sur les nouvelles fonctionnalités de JDK 12 et certaines difficultés que vous pouvez rencontrer lors de la migration vers une nouvelle version.

J'ai écrit plusieurs articles de blog qui répertorient toutes les modifications pour chacune des dernières versions de Java ( JDK 10 , JDK 11 ). J'explorerai maintenant le côté obscur de JDK 12, en me concentrant sur certains des pièges qui peuvent poser des problèmes si vous souhaitez porter l'application sur cette version.



JDK 12 possède le plus petit nombre de nouvelles fonctionnalités de toutes les versions Java à ce jour (j'en ai compté 109 dans JDK 10 et 90 dans JDK 11). Ce n'est pas mal - en raison des cycles de publication, certaines versions contiendront plus de changements et d'autres moins.


Je décomposerai de nouvelles fonctions en domaines logiques évidents: Java, bibliothèques, JVM et autres fonctions JDK.


Changements de langue


La fonction que je (et je suppose que beaucoup d'autres personnes) considéreront la plus visible dans JDK 12 est la nouvelle instruction switch ( JEP 325 ). Il s'agit également du premier changement de langue à utiliser comme fonction de «prévisualisation». L'idée de «prévisualisation» a été introduite début 2018 dans le cadre de JEP 12 . Il s'agit essentiellement d'un moyen d'activer les versions bêta de nouvelles fonctionnalités à l'aide des options de ligne de commande. En utilisant l'aperçu, il est toujours possible d'effectuer des modifications en fonction des commentaires des utilisateurs et, dans le pire des cas, de supprimer complètement une fonction si elle n'a pas été reçue correctement. La clé des fonctions d'aperçu est qu'elles ne sont pas incluses dans la spécification Java SE. À propos du nouveau commutateur, il y a une très bonne traduction sur Habré.
Dans JDK 12, un commutateur est devenu une expression qui évalue son «contenu» pour produire un résultat. J'expliquerai tout de suite que cela n'affecte pas la compatibilité descendante, vous n'avez donc pas besoin de changer de code utilisant Switch comme opérateur.


Je vais utiliser l'exemple de JEP, car il est simple et clair:


Ancien interrupteur
int numLetters; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY: case SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; default: throw new IllegalStateException("Huh? " + day); } 

Comme vous pouvez le voir, nous mappons le jour de la semaine au nom de la variable day , puis numLetters la valeur numLetters . Maintenant que switch est un opérateur, nous pouvons effectuer l'affectation une fois (ce qui réduit considérablement la probabilité d'un code erroné) en utilisant le résultat de l'instruction switch:


 int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; default -> throw new IllegalStateException("Huh? " + day); }; 

Vous remarquerez rapidement deux changements de syntaxe. Les développeurs d'OpenJDK sont tombés sur une fonction de syntaxe peu connue appelée liste séparée par des virgules. L'opérateur d'expression lambda -> facilite également le retour de la valeur. Vous pouvez toujours utiliser break avec une valeur si vous le voulez vraiment. Il existe plusieurs autres détails sur cette fonctionnalité, mais il est probablement plus facile de lire JEP.


Bibliothèques


Il y a un changement que je trouve très utile. Il en existe également plusieurs.


collecteur de départ


L'API Streams, comme d'habitude, a un nouveau collecteur, fourni par la classe utilitaire Collectors. Un nouveau collecteur peut être obtenu en utilisant la méthode teeing() . Le collecteur de départs prend trois arguments: deux collecteurs et une bifonction. Pour comprendre le travail de ce collectionneur, je recommande cet article sur Habré .
Pour comprendre comment il fait ça, j'ai dessiné un schéma:


image

Toutes les valeurs du flux d'entrée sont transmises à chaque collecteur. Le résultat de chaque collecteur est transmis en tant qu'arguments à BiFunction pour générer le résultat final.


Un exemple simple est le calcul de la valeur moyenne (oui, je sais qu'il existe déjà des collecteurs pour cela, comme averagingInt() , mais ceci est un exemple simple pour aider à comprendre le concept).


 /* Assume Collectors is statically imported */ double average = Stream.of(1, 4, 2, 7, 4, 6, 5) .collect(teeing( summingDouble(i -> i), counting(), (sum, n) -> sum / n) ); 

Le premier collecteur calcule la somme du flux d'entrée, et le second - le nombre d'éléments. BiFunction divise la somme par le nombre d'éléments pour obtenir la valeur moyenne.


java.io


InputStream skipNBytes(long n) - ignore et supprime exactement n octets du flux d'entrée InputStream. Si n est égal ou inférieur à zéro, les octets ne sont pas ignorés.


java.lang


Un nouveau package est apparu, java.lang.constant, qui fait partie de l'API JVM constante, JEP 334 .


Chaque fichier de classe Java possède un pool persistant qui stocke des opérandes pour les instructions de bytecode dans la classe. Il est difficile pour les développeurs de manipuler les fichiers de classe en raison de problèmes de chargement des classes. L'API JVM constante fournit des types de référence symboliques pour décrire chaque forme d'une constante (classe, constante chargeable, MethodHandle , constante MethodHandle , constante MethodType ).


Il a également influencé plusieurs autres classes. Toutes les classes suivantes ont désormais une méthode describeConstable() :


  • Classe
  • Double
  • Enum
  • Flotter
  • Entier
  • Long
  • String
  • Methodhandle
  • MethodType
  • Varhandle

En tant que britannique, je trouve ça assez drôle. Le terme Constable, describeConstable utilisé depuis le XIe siècle, et c'est ainsi que nous nous référons souvent aux policiers. C'est aussi le nom du célèbre artiste du XVIIIe siècle, John Constable. Cela me fait me demander si la méthode describeTurner() sera dans une future version. Évidemment, dans ce cas, il s'agit d'une abréviation de la Constant Table , sans lien avec un avocat ou un paysagiste.


Les classes suivantes incluent désormais la méthode resolveConstantDesc() :


  • Double
  • Enum.EnumDesc
  • Flotter
  • Entier
  • Long
  • String

java.lang.Character


Les classes internes ont été mises à jour pour inclure de nouveaux blocs Unicode. J'aime toujours voir ce que les gens ont trouvé à ajouter à Unicode, voici quelques exemples:


  • Symboles d'échecs
  • Numéros mayas
  • Le sogdian est une langue iranienne orientale qui n'était plus utilisée au 11e siècle.
  • Old Sogdian est une version plus ancienne (et, je suppose, encore plus limitée) de Sogdian

java.lang.Class


arrayType() renvoie Class pour le type du tableau dont le type de composant est décrit par cette Class . Cela peut être vérifié à l'aide de jshell :


 jshell> (new String[2]).getClass().getName() $11 ==> "[Ljava.lang.String;" jshell> (new String[2]).getClass().arrayType() $12 ==> class [[Ljava.lang.String; jshell> "foo".getClass().arrayType() $15 ==> class [Ljava.lang.String; 

Je ne suis pas tout à fait sûr de la signification de cette méthode, car elle ne fait qu'ajouter une Class au type que cette classe représente.


componentType() , identique à getComponentType() . La question se pose - pourquoi ajouter une méthode redondante?


descriptorString() - renvoie à nouveau le même résultat que getName() . Cependant, cela est nécessaire car Class implémente désormais l'interface TypeDescriptor associée à la nouvelle API JVM constante.


lava.lang.String


indent() - Ajoute une série d'espaces de début à une chaîne. Si le paramètre est négatif, ce nombre d'espaces de tête sera supprimé (si possible).


transform() - Applique la fonction fournie à une chaîne. Le résultat peut ne pas être une chaîne.


java.lang.invoke


VarHandle maintenant toString() pour renvoyer une description compacte.


java.net.SecureCacheResponse et java.net.ssl.HttpsConnection ont une nouvelle méthode, getSSLSession() qui renvoie Optional contenant la SSLSession utilisée dans la connexion.


java.nio.files


La classe Files possède une nouvelle méthode, mismatch() , qui recherche et renvoie la position du premier octet de non-concordance dans le contenu de deux fichiers, ou -1L s'il n'y a pas de non-concordance.


java.text


Il existe une nouvelle classe CompactNumberFormat . Il s'agit d'une sous-classe de NumberFormat qui formate un nombre décimal sous forme compacte. Un exemple de formulaire compact - 1M au lieu de 1000000 , donc - nécessite deux au lieu de neuf caractères. NumberFormat et java.text.spi.NumberFormatProvider ont été étendus pour inclure la nouvelle méthode getCompactNumberInstance() . Il existe également une nouvelle énumération, NumberFormatStyle qui a deux significations: LONG et SHORT.


java.util.concurrent


CompletionStage comprend désormais plusieurs formulaires surchargés avec trois méthodes:


  • exceptionnellement asynchrone
  • exceptionnellement
  • exceptionnellementComposeAsync

Ces méthodes élargissent les possibilités de création d'un nouveau CompletionStage partir d'un existant, CompletionStage si l'actuel se termine par une exception. Consultez la documentation de l'API pour plus de détails.


javax.crypto


La classe Cipher a une nouvelle toString() qui renvoie une chaîne contenant la transformation, le mode et le fournisseur Cipher .


javax.naming.ldap.spi


Il s'agit d'un nouveau package dans JDK 12 et il contient deux classes: LdapDnsProvider , qui est la classe de fournisseur pour les recherches DNS pendant les opérations LDAP, et LdapDnsProviderResults qui encapsule le résultat de la recherche DNS pour l'URL LDAP.


Swing


Swing est toujours en cours de mise à jour! Oui, filechooser.FileSystemView dispose désormais d'une nouvelle méthode getChooserShortcutPanelFiles() . Il renvoie un tableau de fichiers représentant les valeurs à afficher par défaut dans la barre de raccourcis de sélection de fichiers.


Modifications de la JVM


JEP 189: Shenandoah : ramasseur d'ordures à faible pause


Shenandoah est un projet de recherche annoncé par Red Hat en 2014 qui se concentre sur les exigences des applications à faible latence pour la gestion de la mémoire dans la JVM. Ses objectifs sont un temps de pause maximal de 1 à 10 ms pour un tas de plus de 20 Go ( il n'est donc pas destiné aux petites applications - comme l' un des développeurs de Shenandoah a répondu , ce n'est pas le cas et il fait un excellent travail avec de petites applications). Ce collecteur est conçu pour fonctionner en parallèle avec les threads d'application, évitez donc les problèmes que nous voyons dans la plupart des récupérateurs de place.


JEP 344: Collections mixtes G1


Cette modification vise à améliorer le comportement du collecteur G1 lorsqu'il atteint l'objectif de retard défini. G1 divise l'espace de mémoire (ancien et ancien) en régions. L'idée est que dans l'ancienne génération, vous n'avez pas besoin de collecter les déchets en une seule opération. Lorsque G1 doit collecter des ordures, il sélectionne les régions qu'il définit. C'est ce qu'on appelle un kit de collecte. Avant JDK 12, lorsque les travaux ont commencé sur le plateau, tous les travaux devaient être achevés, essentiellement, comme une opération atomique. Le problème était que, parfois, en raison de changements dans l'utilisation de l'espace de tas par l'application, l'ensemble de collecte s'avérait trop volumineux et prenait trop de temps à collecter, ce qui conduisait au fait que le temps de pause n'était pas atteint.


Dans JDK 12, si G1 identifie cette situation, il interrompra la collecte de données à mi-chemin si cela n'affecte pas la capacité de l'application à continuer d'allouer de l'espace pour de nouveaux objets. L'effet net de G1 sera meilleur lorsqu'un temps de pause court sera atteint.


JEP 346: retourne rapidement la mémoire allouée inutilisée de G1


Il s'agit d'une autre amélioration des performances pour G1, mais une autre est liée à la façon dont la JVM interagit avec le reste du système. De toute évidence, la mémoire est requise pour le tas JVM et, au démarrage, il demande de la mémoire à l'allocateur de mémoire virtuelle du système d'exploitation. Lorsque l'application démarre, il peut arriver que la quantité de mémoire requise pour le segment de mémoire diminue et qu'une partie de la mémoire allouée puisse être renvoyée au système d'exploitation pour être utilisée par d'autres applications.


G1 le fait déjà, mais ne peut le faire qu'à deux endroits. D'une part, lors d'une collection complète, et d'autre part, lors d'un des cycles parallèles. G1 essaie de ne pas effectuer de collecte complète et avec une faible utilisation de la mémoire, il peut y avoir des périodes importantes entre les cycles de collecte. Cela conduit au fait que G1 peut conserver une mémoire fixe pendant une longue période.


Dans JDK 12, G1 essaiera périodiquement de continuer ou d'exécuter une boucle parallèle pendant que l'application est inactive pour déterminer l'utilisation globale du tas Java. La mémoire inutilisée peut être retournée au système d'exploitation de manière plus rapide et prévisible.


Le nouvel indicateur de ligne de commande -XX:G1PeriodicGCInterval peut être utilisé pour définir le nombre de millisecondes entre les vérifications.


Cette fonctionnalité entraînera une utilisation plus conservatrice de la mémoire JVM pour les applications qui ont été inactives pendant de longues périodes.


Autres nouvelles fonctionnalités JDK


JEP 230: Kit de micro-analyse comparative


Java Microbenchmarking Harness (JMH) a été développé par Alexey Shipilev lorsqu'il travaillait chez Oracle et fournit une plate-forme étendue pour développer des tests de performances pour les applications Java. Alexey a fait un travail remarquable en aidant les gens à éviter de nombreuses erreurs simples qu'ils font en essayant d'analyser les performances des applications: échauffement, éviter les exceptions, etc.


Maintenant, JMH peut être inclus dans OpenJDK. Quiconque souhaite travailler sur le JDK lui-même et changer le code peut l'utiliser pour comparer les performances avant et après leurs modifications, ainsi que pour comparer les performances dans différentes versions. Un certain nombre de tests sont inclus pour permettre les tests; La conception de JMH est telle qu'il est facile d'ajouter de nouveaux tests là où cela est nécessaire.


JEP 340: un port Aarch64, pas deux


OpenJDK possède deux ports pour l'architecture Arm64, l'un fourni par Oracle et l'autre par Red Hat. Comme cela n'était pas nécessaire et qu'Oracle a cessé de prendre en charge Arm pour ses binaires JDK, il a été décidé d'utiliser uniquement le port Red Hat, qui est toujours pris en charge et développé.


JEP 341: archives CDS par défaut


La classe de partage de données (CDS) était auparavant une fonctionnalité commerciale d'Oracle JDK. Avec une transition récente effectuée dans JDK 11 pour éliminer toutes les différences fonctionnelles entre Oracle JDK et OpenJDK, il a été inclus dans OpenJDK.


Pour utiliser CDS, vous avez besoin d'une archive créée pour les classes qui se chargent au démarrage de l'application. JDK 12 pour les plates-formes 64 bits a désormais le fichier classes.jsa dans le répertoire lib/server . Il s'agit de l'archive CDS pour les «classes par défaut». Je suppose que cela signifie toutes les classes publiques dans les modules JDK; Je n'ai pas trouvé de moyen de le déballer pour vérifier. Étant donné que CDS est activé par défaut, ce qui équivaut à l'option -Xshare:auto sur la ligne de commande, les utilisateurs bénéficieront de temps de démarrage de l'application améliorés.


Conclusions


JDK 12 fournit un petit nombre de nouvelles fonctions et API, la switch étant la plus intéressante pour les développeurs. Les utilisateurs de G1 apprécieront certainement les améliorations de performances.


Avec la nouvelle version de la version, je conseillerais à tous les utilisateurs de tester leurs applications dans cette version. Le suivi des modifications incrémentielles vous aidera à éviter les surprises si vous décidez de passer à la prochaine version du support à long terme.


Nous avons des versions JDK 12 gratuites pour Zulu Community Edition pour vous aider avec vos tests. Assurez-vous de les essayer.

Source: https://habr.com/ru/post/fr446590/


All Articles