JDK 17 Nouveautés

Contexte

La version 17 du JDK est disponible depuis mardi dernier. Les autres distributions (Adoptium, Liberica, Azul..) vont suivre selon leur chaine de construction. A travers différents billets, nous avons déjà eu l’occasion de voir certaines fonctionnalités. C’est l’occasion de faire une synthèse sur l’ensemble des nouveautés.

La version 17 devient la nouvelle version LTS (Long Term Support).

En collaboration avec la communité et le JCP, Oracle propose d’accèlerer le rythme des versions LTS. La prochaine version pourrait être Java 21 disponible en septembre 2023, soit 2 ans au lieu de 3 ans actuellement.

Nouvelles fonctionnalités

306 - Restore Always-Strict Floating-Point Semantics

Cela concerne les contributeurs d’OpenJDK. L’objectif est d’utiliser, comme à l’origine, systématiquement les opérations de virgules flottantes de manière strict.

356 - Enhanced Pseudo-Random Number Generators

L’objectif est de fourni de nouveaux types et de nouvelles implémentations pour la génération des nombres aléatoires. Les buts sont :

  • Pouvoir facilement utiliser plusieurs algorithmes de génération de nombre aléatoires de manière interchangeable

  • Améliorer le support des flux ("stream")

  • Eliminer le code dupliqué des classes existantes

  • Ne pas changer le comportement de la classe java.util.Random

382 - New macOS Rendering Pipeline

En 2018, Apple annonce un nouveau cadriciel nommé Metal pour macOS 10.14. Ce dernier va remplacer la librairie OpenGL qui devient dépréciée.

Le projet Lanai est lancé en août 2019 pour prendre en compte le nouveau cadriciel. Cette fonctionnalité n’est ni plus ni moins l’intégration de ses travaux dans le JDK.

La mise en oeuvre consiste à :

  • Reprendre toutes les fonctionnalités de l’API Java 2D

  • Mettre en place la coexistence avec l’implémentation OpenGL

  • Etre prêt quand Apple supprimera OpenGL

  • Etre transparent pour les utilisateurs

  • Fournir les mêmes performances (voir meilleure)

Par défaut, c’est l’implémentation OpenGL qui est utilisé. Si vous souhaitez utiliser la nouvelle implémentation est faudra ajouter la propriété suivante :

-Dsun.java2d.metal=true

avertissementPlus d’informations sur le billet dédié au nouveauté JDK17 pour macOS.

403 - Strongly Encapsulate JDK Internals

L’objectif est de continuer à pousser les développeurs à ne pas utiliser les classes internes du JDK. Pour cela, l’option --illegal-access affiche maintenant uniquement un avertissement quelque soit la valeur du paramètre et sera ignorée.

OpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit; support was removed in 17.0

L’option sera retirée dans une future release.

Il reste encore possible d’accèder à ces classes :

  • l’option --add-opens,

  • l’attribut du manifest Add-Opens.

La classe sun.misc.Unsafe reste accessible.

avertissementRetrouver les informations sur le billet sur JEP 396.

409 - Sealed Classes

Les classes scellées sont un moyen pour le développeur d’avoir plus de contrôle sur l’héritage. Pour cela, deux nouveaux mot clés ont été introduite sealed et non-sealed :

  • sealed : permet d’avoir des classes dérivées à condition qu’elles fassent partir des classes autorisées pour cela il y a le mot clé permits à utiliser.

  • non-sealed : permet de ne pas limiter les classes dérivées.

Par exemple, nous avons :

package fr.exemple.geometrie;

public abstract sealed class Forme
    permits Cercle, Rectangle {
	...
}

Nous définissons une classe abstraite Forme dont seules les classes Cercle et Rectangle seront autorisées comme classes dérivées.

avertissementPlus d’informations sur le billet dédié.

415 - Implement Context-Specific Deserialization Filters

La sérialisation non sécurisée fait partie du OWASP TOP 10 des vulnérabilités des applications web : A8:2017-Insecure Deserialization

C’est une amélioration de la JEP 290 qui permet déjà de mettre en place un filtre avant la sérialisation. Ainsi, il est possible de protéger notre application de ce type d’attaques.

Pour cela, nous avons une interface à notre disposition :

interface ObjectInputFilter {
    Status checkInput(FilterInput filterInfo);

    enum Status {
        UNDECIDED,
        ALLOWED,
        REJECTED;
    }

    ...
}

Il est aussi possible de passer simplement par la ligne de commande avec la propriété jdk.serialFilter.

java -Djdk.serialFilter="fr.lbenoit.exemple*;java.base/*;!*" ...

astuceCela permet de définir facilement une liste blanche de classes et/ou packages autorisées.

L’amélioration consiste à pouvoir définir un filtre par contexte de désérialisation. Une nouvelle interface BinaryOperator<ObjectInputFilter> a été mise en place pour permettre de savoir quelle filtre utilisé selon le contexte.

Nous pouvons réaliser l’implémentation de la méthode apply(…​)

public class FiltreSelonContexte implements BinaryOperator<ObjectInputFilter> {

    public ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter next) {
        ....
    }
}

Cela permet de choisir entre l’implémentation courante et une nouvelle selon notre contexte. En sachant, que maintenant, il est aussi possible de fusionner les deux filtres :

interface ObjectInputFilter {
    ObjectInputFilter ObjectInputFilter.merge(ObjectInputFilter premier, ObjectInputFilter second);
}

avertissementPlus d’informations sur le billet dédié.

Nouvelles fonctionnalités (Portage)

391 - macOS/AArch64 Port

Le portage consiste à pouvoir faire fonctionner la JVM sur les nouvelles puces M1 d’Apple. L’architecture est ARM64, correspond à ce qu’on appelle AArh64.

Cela fait suite au portage de ce type d’architecture pour Linux, Windows et donc MacOS maintenant.

avertissementPlus d’informations sur le sur le billet dédié.

Fonctionnalités en mode Aperçu

406 - Pattern Matching for switch (Preview)

Les expressions switch ont été introduits dans le JDK 14 à travers la JEP 361

L’objectif de cette fonctionnalité est de mettre en place le filtrage par motif au niveau des expressions switch.

Regardons un exemple. L’ancien code ressemble à cela (avec l’utilisation du filtrage par motif pour instanceof) :

static String formatter(Object o) {
    String formatted = "unknown";
    if (o instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (o instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (o instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (o instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;
}

Avec le filtrage par motif au niveau des switch, nous obtenons le code suivant :

static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();
    };
}

Ce dernier est beaucoup plus clair et concis.

avertissementPlus d’informations sur le billet dédié.

Fonctionnalités en mode Incubation

412 - Foreign Function & Memory API (Incubator)

Foreign Memory API a été proposé en mode incubation dans le JDK 14, puis ré-incubé dans le JDK 15 et JDK16.

D’un autre côté, Foreign Linker API a été introduit la première fois en mode incubation dans le JDK 16.

L’objectif de cette fonctionnalité (Foreign Function & Memory API) est de réunir les deux fonctionnalités en une seule ayant comme but :

  • Etre facile à utiliser,

  • Avoir des performances comparables, voir meilleur, à sun.misc.Unsafe et JNI,

  • Fournir une voie générale pour l’allocation de la mémoire étrangère,

  • Désactiver les opérations dangereuses par défaut.

Les travaux sont menés dans le cadre du projet Panama. L’objectif de ce dernier est d’améliorer les interactions du code Java et non-Java de l’application.

414 - Vector API (Second Incubator)

L’API Vectorielle a été proposée la première fois dans le JDK 16.

L’objectif est de fournir une API afin de fournir un mécanisme pour exprimer des calculs vectoriels. Elle utilise les instructions vectorielles optimales sur les architectures CPU prises en charge. Cela permet d’obtenir des performances accrues vis à vis des calculs scalaires

Les performances ont été améliorées dans cette version. Notamment, pour traduire les vecteurs d’objets vers et depuis les tableaux booléens.

Fonctionnalités dépréciées

398 - Deprecate the Applet API for Removal

Bien que les applets ont permis de rendre le langage populaire, ils ne sont plus supportés par les navigateurs modernes.

Elles étaient dépréciées avec le JDK 9 à travers la JEP 289: Deprecate the Applet API).

Une nouvelle étape est franchie avec l’annonce de dépréciation pour suppression.

avertissementPlus d’informations sur le chapitre dédié.

411 - Deprecate the Security Manager for Removal

Cela était moins attendu que la dépréciation des applets. Mais effectivement l’équipe a souhaité les lier du fait que le système de sandbox est vraiment utile pour les applets.

En effet, cela était rarement utilisé côté serveur.

Il n’y a pas d’alternatives proposées au gestionnaire de sécurité. En revanche, des pistes sont explorées :

avertissementPlus d’informations sur le chapitre dédié.

Fonctionnalités supprimées

407 - Remove RMI Activation

RMI (Remote Method Invocation) est utilisé pour réaliser la communication via des objets distribués. L’activation RMI est le principe d’avoir un daemon permettant de démarrer l’objet car cela est nécessaire.

L’objectif était de limiter les ressources, car tous les objets distribués n’ont plus besoin d’être en fonctionnement.

A noter que cette fonctionnalité est peu ou pas utilisé par la communauté.

De plus, généralement les communications distribuées passent par des procoles de plus haut niveau : HTTP ou gRPC par exemple.

avertissementPlus d’informations sur le chapitre dédié.

410 - Remove the Experimental AOT and JIT Compiler

Les deux compilateurs expérimentaux AOT et JIT ont servis de base au projet graalvm.

  • Le JIT (Just-In-Time) a besoin que la JVM tourne pour commencer les optimisations du code appelé fréquemment (compilateur à la volée). C’est la fameuse phase de "warm-up" de la JVM.

  • L’AOT consiste à réaliser la compilation native au lieu du code intermédiaire. Ainsi, les performances sont optimales dès le début.

Les travaux ont permis d’avoir beaucoup de retour et d’informations pour la mise en place de ces solutions. Cela a conforté la direction de solution "Java-on-Java".

avertissementPlus d’informations sur le chapitre dédié.