Les nouveautés de Java 17

Introduction

Dans cet article, nous allons parler des nouveautés de la nouvelle version de l’écosystème Java, Java SE 17 – les nouvelles fonctionnalités et les changements apportés à son processus de release, au support LTS et aux licences.

Liste des JEPs

Tout d’abord, examinons ce qui peut affecter le travail quotidien dans la vie des développeurs Java.

Restaurer la sémantique Always-Strict de la virgule flottante (JEP 306)

Cette JEP est principalement destinée aux applications scientifiques, et elle rend les opérations en virgule flottante systématiquement strictes. Les opérations en virgule flottante par défaut sont strict ou strictfp, qui garantissent toutes deux les mêmes résultats des calculs en virgule flottante sur toutes les plates-formes.

Avant Java 1.2, le comportement strictfp était également le comportement par défaut. Toutefois, en raison de problèmes matériels, les architectes ont changé, et le mot-clé strictfp était nécessaire pour réactiver ce comportement. Il n’est donc plus nécessaire d’utiliser ce mot-clé.

Générateurs de nombres pseudo-aléatoires améliorés (JEP 356)

Également liée à des cas d’utilisation plus particuliers, la JEP 356 fournit de nouvelles interfaces et implémentations pour les générateurs de nombres pseudo-aléatoires (PRNG). Ainsi, il est plus facile d’utiliser divers algorithmes de manière interchangeable, et elle offre également un meilleur support pour la programmation basée sur les streams, comme nous allons le démontrer brièvement :

public IntStream getPseudoInts(String algorithme, int tailleStream) {
    // renvoie un IntStream de taille @tailleStream de nombres aléatoires générés par l'@algorithme
    // où la borne inférieure est 0 et la borne supérieure est 100 (exclusif).
    return RandomGeneratorFactory.of(algorithme)
            .create()
            .ints(tailleStream, 0,100);
}

Les anciennes classes aléatoires, telles que java.util.Random, SplittableRandom et SecureRandom, étendent désormais la nouvelle interface RandomGenerator.

Nouveau système de rendu pour macOS (JEP 382)

Cette JEP implémente un pipeline de rendu interne Java 2D pour macOS, car Apple a déprécié l’API OpenGL (dans macOS 10.14) utilisée en interne dans Swing GUI. La nouvelle implémentation utilise l’API Metal d’Apple.

macOS/AArch64 Port (JEP 391)

Apple a annoncé un plan à long terme pour faire passer sa gamme d’ordinateurs de X64 à AArch64. Ce JEP adapte le JDK pour qu’il fonctionne sur AArch64 dans les environnements macOS.

Dépréciation de l’API Applet pour la supprimé dans le futur (JEP 398)

Bien que cela puisse être triste pour de nombreux développeurs Java qui ont commencé leur carrière de développement en utilisant les API Applet, de nombreux navigateurs Web ont déjà supprimé leur prise en charge du plugin Java. L’API est devenue inutile et cette version l’a marquée pour être retirée, même si elle est marquée comme obsolète depuis la version 9.

Strongly Encapsulate JDK Internals (JEP 403)

La JEP 403 représente un pas de plus vers une forte encapsulation des éléments internes du JDK, car elle supprime le flag -illegal-access. La plate-forme va ignorer ce flag, et si le flag est présent, la console va émettre un message informant de la suppression du flag.

Cette fonctionnalité empêchera les utilisateurs du JDK d’accéder aux API internes, à l’exception des API critiques comme sun.misc.Unsafe.

Pattern Matching dans les Switch (Preview)  (JEP 406)

Un autre pas vers pattern matching en l’améliorant pour les expressions et les instructions switch. Cela va réduire le boilerplate nécessaire à la définition de ces expressions et améliorer l’expressivité du langage. Voyons deux exemples de ces nouvelles capacités :

static record Human (String name, int age, String profession) {}

public String checkObject(Object obj) {
    return switch (obj) {
        case Human h -> "Name: %s, age: %s and profession: %s".formatted(h.name(), h.age(), h.profession());
        case Circle c -> "This is a circle";
        case Shape s -> "It is just a shape";
        case null -> "It is null";
        default -> "It is an object";
    };
}

public String checkShape(Shape shape) {
    return switch (shape) {
        case Triangle t && (t.getNumberOfSides() != 3) -> "This is a weird triangle";
        case Circle c && (c.getNumberOfSides() != 0) -> "This is a weird circle";
        default -> "Just a normal shape";
    };
}

Suppression de l’activation RMI (JEP 407)

Marquée pour une suppression dans la version 15, cette JEP a retiré l’API d’activation RMI dans la version 17.

Classes scellées (JEP 409)

Les classes scellées font partie du projet Amber, et cette JEP introduit officiellement une nouvelle fonctionnalité dans le langagealors qu’elle était disponible en mode en mode preview dans les versions 15 et 16 du JDK.

Cette fonctionnalité limite les classes ou interfaces qui peuvent étendre ou implémenter un composant scellé. Une autre amélioration liée au pattern matching combinée au JEP 406 permettra une inspection plus sophistiquée et plus propre du pattern de code type, cast et act. Voyons cela en action :

int getNumberOfSides(Shape shape) {
    return switch (shape) {
        case WeirdTriangle t -> t.getNumberOfSides();
        case Circle c -> c.getNumberOfSides();
        case Triangle t -> t.getNumberOfSides();
        case Rectangle r -> r.getNumberOfSides();
        case Square s -> s.getNumberOfSides();
    };
}

Suppression de l’AOT expérimental et du compilateur JIT (JEP 410)

Introduits dans le JDK 9 et le JDK 10, respectivement, en tant que fonctionnalités expérimentales, la compilation Ahead-Of-Time (AOT) (JEP 295) et le compilateur Just-In-Time (JIT) de GraalVM (JEP-317) étaient des fonctionnalités ayant un coût de maintenance élevé. D’autre part, elles n’ont pas été adoptées de manière significative. Pour cette raison, cette JEP les a supprimées de la plate-forme, mais les développeurs peuvent toujours les exploiter en utilisant GraalVM.

Fonction étrangère et API mémoire (Incubator) (JEP 412)

Les API Foreign Function et Memory permettent aux développeurs Java d’accéder au code depuis l’extérieur de la JVM et de gérer la mémoire hors du heap. L’objectif est de remplacer l’API JNI et d’améliorer la sécurité et les performances par rapport à la version précédente. Cette API est une autre fonctionnalité développée par le projet Panama, et elle a été évoluée et a été précédée par les JEP 393, 389, 383 et 370.

Avec cette fonctionnalité, nous pouvons faire un appel à une bibliothèque C à partir d’une classe Java :

private static final SymbolLookup libLookup;

static {
    // loads a particular C library
    var path = JEP412.class.getResource("/print_name.so").getPath();
    System.load(path);
    libLookup = SymbolLookup.loaderLookup();
}

Tout d’abord, il est nécessaire de charger la bibliothèque cible que nous souhaitons appeler via l’API (comme indiqué ci-dessus). Ensuite, nous devons spécifier la signature de la méthode cible et enfin l’appeler :

public String getPrintNameFormat(String name) {

    var printMethod = libLookup.lookup("printName");

    if (printMethod.isPresent()) {
        var methodReference = CLinker.getInstance()
            .downcallHandle(
                printMethod.get(),
                MethodType.methodType(MemoryAddress.class, MemoryAddress.class),
                FunctionDescriptor.of(CLinker.C_POINTER, CLinker.C_POINTER)
            );

        try {
            var nativeString = CLinker.toCString(name, newImplicitScope());
            var invokeReturn = methodReference.invoke(nativeString.address());
            var memoryAddress = (MemoryAddress) invokeReturn;
            return CLinker.toJavaString(memoryAddress);
        } catch (Throwable throwable) {
            throw new RuntimeException(throwable);
        }
    }
    throw new RuntimeException("printName function not found.");
}

L’API Vector (Second Incubator) (JEP 414)

L’API Vector traite les opérations de type SIMD (single instruction multiple data), c’est-à-dire plusieurs ensembles d’instructions s’exécutant en parallèle. Elle exploite la CPU qui prend en charge les instructions vectorielles et permet l’exécution de ces instructions sous forme de pipelines. Par conséquent, la nouvelle API permettra aux développeurs de mettre en œuvre un code plus efficace, en tirant parti du potentiel du matériel.

Les cas d’utilisation quotidiens de cette opération sont les applications linéaires scientifiques, le traitement d’images, le traitement de caractères, et toute application arithmétique lourde ou toute application qui doit réaliser une opération pour de multiples opérandes indépendants.

Nous allons utiliser l’API pour illustrer un exemple simple de multiplication vectorielle :

public void newVectorComputation(float[] a, float[] b, float[] c) {
    for (var i = 0; i < a.length; i += SPECIES.length()) {
        var m = SPECIES.indexInRange(i, a.length);
        var va = FloatVector.fromArray(SPECIES, a, i, m);
        var vb = FloatVector.fromArray(SPECIES, b, i, m);
        var vc = va.mul(vb);
        vc.intoArray(c, i, m);
    }
}

public void commonVectorComputation(float[] a, float[] b, float[] c) {
    for (var i = 0; i < a.length; i ++) {
        c[i] = a[i] * b[i];
    }
}

Filtres de désérialisation spécifiques au contexte (JEP 415)

La JEP 290, introduite pour la première fois dans le JDK 9, nous a permis de valider les données sérialisées entrantes en provenance de sources non-fiables, une origine de beaucoup de problèmes de sécurité. Cette validation se fait au niveau de la JVM, ce qui offre plus de sécurité et de robustesse. Avec JEP 415, les applications peuvent configurer des filtres de désérialisation spécifiques au contexte et sélectionnés dynamiquement, définis au niveau de la JVM. Chaque opération de désérialisation fera appel à ces filtres.

Définition de LTS

Les changements ne se limitent pas au code, les processus changent également. Comme nous le savons peut-être, l’histoire des versions de la JDK Java était largement connue pour être longue et imprécise. Bien qu’elle ait été conçue pour avoir une cadence de trois ans entre les versions, elle est souvent devenue un exercice de quatre ans.

De plus, étant donné la nouvelle dynamique du marché où l’innovation et la réactivité sont devenues indispensables, l’équipe responsable de l’évolution de la JDK a décidé de modifier la fréquence des versions pour s’adapter à cette réalité. Par conséquent, un nouveau modèle de publication de fonctionnalités à six mois a été adopté depuis Java 10 (publié le 20 mars 2018).

Modèle de publication de six mois

Le nouveau modèle de publication des fonctionnalités, d’une durée de six mois, permet aux développeurs de la JDK de publier les fonctionnalités lorsqu’elles sont prêtes. Ainsi, il élimine la pression de pousser les fonctionnalités dans la nouvelle version. Sinon, ils devraient attendre trois ou quatre ans pour mettre les fonctionnalités à la disposition des utilisateurs de la plate-forme.

Le nouveau modèle améliore également le cycle de feedback entre les utilisateurs et les architectes de la JDK. En fait, les fonctionnalités peuvent être mises à disposition dans un mode d’incubation et ne sont diffusées pour un usage général qu’après plusieurs interactions.

Modèle LTS

Puisque les applications des entreprises utilisent largement Java, la stabilité est essentielle. En outre, il est coûteux de continuer d’assurer le support et de fournir des mises à jour pour toutes les versions. C’est pour cette raison que les versions LTS (Long Term Support) ont été créées, offrant aux utilisateurs un support étendu. Ces versions deviennent donc naturellement plus stables et plus sûres grâce aux corrections de bogues, aux améliorations des performances et aux correctifs de sécurité. Dans le cas d’Oracle, ce support dure généralement huit ans.

Depuis l’introduction des changements dans le modèle de publication, les versions LTS étaient Java SE 11 (sortie en septembre 2018) et Java SE 17 (sortie en septembre 2021). Néanmoins, la version 17 a apporté quelque chose de nouveau au modèle. En bref, l’intervalle entre les versions LTS est désormais de deux ans au lieu de trois, ce qui fait que Java 21 (prévue pour septembre 2023) sera probablement la prochaine LTS.

Un autre point qui mérite d’être signalé est que ce modèle de version n’est pas nouveau. Il a été copié sans vergogne et adapté d’autres projets comme Mozilla Firefox, Ubuntu et d’autres où le modèle a fait ses preuves.

Processus des nouvelles versions

Nous nous sommes basés sur la JEP 3 pour rédiger cet article, étant donné qu’il décrit tous les changements intervenus dans le processus. Veuillez le consulter pour plus de détails. Nous allons essayer d’en faire un résumé concis ici.

Compte tenu du nouveau modèle décrit ci-dessus, combiné au développement continu de la JDK et aux nouvelles cadences de publication semestrielles (généralement juin et décembre), Java évoluera plus rapidement. L’équipe de développement du JDK lancera le cycle de publication de la prochaine version de fonctionnalité en suivant le processus décrit ci-après.

Quelle est la suite ?

Les architectes du JDK continuent à travailler sur de nombreux projets qui visent à moderniser le système. L’objectif est de fournir une meilleure expérience de développement et des API plus robustes et performantes.

Par conséquent, le JDK 18 devrait sortir dans six mois, même si cette version ne devrait pas contenir de changements importants ou révolutionnaires. Nous pouvons suivre la liste des JEP proposées et ciblées pour cette version sur le site officiel du projet OpenJDK.

Une autre nouvelle pertinente qui affecte les versions actuelles et futures est la nouvelle licence gratuite appliquée à la distribution Oracle JDK (ou Hotspot). Dans la plupart des cas, Oracle offre sa distribution gratuitement pour les environnements de production et autres, mais il y a quelques exceptions. Donc, encore une fois, veuillez vous référer au lien.

Comme mentionné précédemment, le nouveau processus vise à ce que la prochaine version LTS soit la version 21, et le plan est de la publier d’ici septembre 2023.

Conclusion

Dans cet article, nous avons abordé l’actualité de la nouvelle version de Java 17, en passant en revue ses développements récents, ses nouvelles possibilités, la définition du support et le processus du cycle de publication.

Laisser un commentaire