IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Java 19 : nouvelles fonctionnalités avec exemples
Elle apporte des méthodes pour créer des HashMaps préalloués

Le , par Bruno

23PARTAGES

12  0 
Java 19 est dans la phase dite Rampdown Phase One depuis le 9 juin 2022, ce qui signifie qu'aucune autre proposition d'amélioration du JDK (JEP) ne sera incluse dans la version. L'ensemble des fonctionnalités est donc fixé. Seuls les bogues seront corrigés, et, si nécessaire, des améliorations mineures seront apportées. Le kit de développement Java 19, prévu pour septembre prochain, est désormais complet et fait l'objet d'une deuxième phase de lancement.

Si une application existante est exécutée avec Java 19, il est possible de voir des points d'interrogation sur la console au lieu de caractères spéciaux. Cela est dû au fait que, depuis Java 19, l'encodage par défaut du système d'exploitation est utilisé pour l'impression dans System.out et System.err par exemple, "Cp1252" sous Windows.


Pour changer la sortie en UTF-8, vous devez ajouter les options VM suivantes lorsque vous appelez l'application :

-Dstdout.encoding=utf8 -Dstderr.encoding=utf8

Si vous ne voulez pas faire cela à chaque fois que vous démarrez le programme, vous pouvez également définir ces paramètres de manière globale en définissant la variable d'environnement suivante :

_JAVA_OPTIONS="-Dstdout.encoding=utf8 -Dstderr.encoding=utf8"

Nouvelles méthodes pour créer des HashMaps préalloués

Si nous voulons créer une ArrayList pour un nombre connu d'éléments (par exemple, 120), nous pouvons le faire comme suit depuis toujours :

List<String> list = new ArrayList<>(120);

Ainsi, le tableau sous-jacent à ArrayList est alloué directement pour 120 éléments et ne doit pas être agrandi plusieurs fois (c'est-à-dire nouvellement créé et copié) pour insérer les 120 éléments. De même, nous avons toujours été en mesure de générer un HashMap comme suit :

Map<String, Integer> map = new HashMap<>(120);

« Intuitivement, on pourrait penser que cette HashMap offre de l'espace pour 120 mappings. Ce qui n'est pas le cas », précise Sven Woltmann, développeur Java. Le HashMap est initialisé avec un facteur de charge par défaut de 0,75. Cela signifie que dès que le HashMap est rempli à 75 %, il est reconstruit ("rehashed") avec une taille double. Cela permet de s'assurer que les éléments sont répartis aussi uniformément que possible dans les buckets de la HashMap et que le moins de buckets possible contiennent plus d'un élément.

Ainsi, le HashMap initialisé avec une capacité de 120 ne peut contenir que 120 × 0,75 = 90 mappings. Pour créer un HashMap pour 120 mappings, vous avez dû calculer la capacité en divisant le nombre de mappings par le facteur de charge : 120 ÷ 0,75 = 160. Il fallait donc créer un HashMap pour 120 mappings comme suit :

Code : Sélectionner tout
1
2
// for 120 mappings: 120 / 0.75 = 160 
Map<String, Integer> map = new HashMap<>(160);

Java 19 nous facilite la tâche ; nous pouvons maintenant écrire ce qui suit à la place :

Map<String, Integer> map = HashMap.newHashMap(120);

Si nous regardons le code source des nouvelles méthodes, nous constatons qu'elles font la même chose que précédemment :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
public static <K, V> HashMap<K, V> newHashMap(int numMappings) { 
    return new HashMap<>(calculateHashMapCapacity(numMappings)); 
} 
 
static final float DEFAULT_LOAD_FACTOR = 0.75f; 
 
static int calculateHashMapCapacity(int numMappings) { 
    return (int) Math.ceil(numMappings / (double) DEFAULT_LOAD_FACTOR); 
}

La méthode newHashMap() a également été ajoutée à LinkedHashMap et WeakHashMap.

La concurrence structurée, en phase d'incubation, est destinée à simplifier la programmation multithread grâce à une API de concurrence structurée. Cette concurrence traite plusieurs tâches exécutées dans différents threads comme une seule unité de travail, afin de rationaliser la gestion des erreurs et l'annulation. La fiabilité et l'observabilité sont améliorées. Pour ceux qui ont besoin d'accéder à du code non-Java (par exemple, la bibliothèque standard C), il y a aussi de bonnes nouvelles : l'API Foreign Function & Memory a atteint le stade de l'aperçu après cinq cycles d'incubation.

Si une tâche se compose de différentes sous-tâches qui peuvent être exécutées en parallèle (par exemple, l'accès aux données d'une base de données, l'appel d'une API distante et le chargement d'un fichier), nous pouvions jusqu'à présent utiliser le framework d'exécution Java pour cela. Cela pourrait alors ressembler à ceci, par exemple :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private final ExecutorService executor = Executors.newCachedThreadPool(); 
 
public Invoice createInvoice(int orderId, int customerId, String language) 
    throws ExecutionException, InterruptedException { 
  Future<Order> orderFuture = 
      executor.submit(() -> loadOrderFromOrderService(orderId)); 
 
  Future<Customer> customerFuture = 
      executor.submit(() -> loadCustomerFromDatabase(customerId)); 
 
  Future<String> invoiceTemplateFuture = 
      executor.submit(() -> loadInvoiceTemplateFromFile(language)); 
 
  Order order = orderFuture.get(); 
  Customer customer = customerFuture.get(); 
  String invoiceTemplate = invoiceTemplateFuture.get(); 
 
  return Invoice.generate(order, customer, invoiceTemplate); 
}

En utilisant un StructuredTaskScope, nous pouvons réécrire l'exemple comme suit :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Invoice createInvoice(int orderId, int customerId, String language) 
    throws ExecutionException, InterruptedException { 
  try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { 
    Future<Order> orderFuture = 
        scope.fork(() -> loadOrderFromOrderService(orderId)); 
 
    Future<Customer> customerFuture = 
        scope.fork(() -> loadCustomerFromDatabase(customerId)); 
 
    Future<String> invoiceTemplateFuture = 
        scope.fork(() -> loadInvoiceTemplateFromFile(language)); 
 
    scope.join(); 
    scope.throwIfFailed(); 
 
    Order order = orderFuture.resultNow(); 
    Customer customer = customerFuture.resultNow(); 
    String invoiceTemplate = invoiceTemplateFuture.resultNow(); 
 
    return new Invoice(order, customer, invoiceTemplate); 
  } 
}

ExecutorService est remplacé dans le scope de la classe par un StructuredTaskScope situé dans le scope de la méthode - et [C=Java]executor.submit() par scope.fork(). En utilisant scope.join(), nous attendons que toutes les tâches soient terminées ou qu'au moins une d'entre elles échoue ou soit annulée. Dans ces deux derniers cas, la méthode throwIfFailed() qui suit lance une ExecutionException ou une CancellationException.

Un aperçu d'une fonction étrangère et d'une API de mémoire, qui introduirait une API par laquelle les programmes Java peuvent interagir avec du code et des données en dehors du runtime Java. En invoquant efficacement des fonctions étrangères (c'est-à-dire du code extérieur à la JVM) et en accédant en toute sécurité à la mémoire étrangère (c'est-à-dire la mémoire non gérée par la JVM), l'API permet aux programmes Java d'appeler des bibliothèques natives et de traiter des données natives sans le danger et la fragilité de l'interface Java Native (JNI).

L'API de fonction et de mémoire étrangères combine deux API antérieures en incubation : l'API d'accès à la mémoire étrangère et l'API de linker étrangère. L'API de fonction et de mémoire étrangères a été incubée dans le JDK 17 et réincubée dans le JDK 18. Les objectifs de la proposition comprennent la facilité d'utilisation, les performances, la généralité et la sécurité. Voici un exemple simple qui stocke une chaîne de caractères dans la mémoire off-heap et appelle la fonction strlen de la bibliothèque standard du C sur celle-ci :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class FFMTest { 
  public static void main(String[] args) throws Throwable { 
    // 1. Get a lookup object for commonly used libraries 
    SymbolLookup stdlib = Linker.nativeLinker().defaultLookup(); 
 
    // 2. Get a handle to the "strlen" function in the C standard library 
    MethodHandle strlen = Linker.nativeLinker().downcallHandle( 
        stdlib.lookup("strlen").orElseThrow(),  
        FunctionDescriptor.of(JAVA_LONG, ADDRESS)); 
 
    // 3. Convert Java String to C string and store it in off-heap memory 
    MemorySegment str = implicitAllocator().allocateUtf8String("Happy Coding!"); 
 
    // 4. Invoke the foreign function 
    long len = (long) strlen.invoke(str); 
 
    System.out.println("len = " + len); 
  } 
}

La FunctionDescriptor de la ligne 9 est intéressant : il attend comme premier paramètre le type de retour de la fonction et comme paramètres supplémentaires les arguments de la fonction. La FunctionDescriptor garantit que tous les types Java sont correctement convertis en types C et vice versa.

Une Preview des modèles d'enregistrement, pour déconstruire les valeurs d'enregistrement. Les modèles d'enregistrement et les modèles de type peuvent être imbriqués pour permettre une forme déclarative, puissante et composable de navigation et de traitement des données. Les objectifs de la proposition comprennent l'extension du filtrage pour exprimer des requêtes de données plus sophistiquées et composables, sans modifier la syntaxe ou la sémantique des patrons de type. Cette proposition s'appuie sur le filtrage de motifs pour instanceof, livré dans le JDK 16 en mars 2021.

Les plans futurs peuvent prévoir l'extension des modèles d'enregistrement avec des capacités telles que les modèles de tableaux et les modèles de variables. Les modèles d'enregistrement font partie du projet Amber, un effort visant à explorer et à incuber des fonctionnalités Java plus petites et orientées vers la productivité.

Source : Java 19

Et vous ?

Quel est votre avis sur le sujet ?

Les exemples présentés par le développeur Sven Woltmann sont-ils pertinents ?

Voir aussi :

JDK 19 : les nouvelles fonctionnalités de Java 19 incluent la concurrence structurée, les modèles d'enregistrement et l'aperçu d'une API de fonction et de mémoire étrangères

JDK 18, l'implémentation de référence de Java 18, est désormais disponible, elle propose comme Python, Ruby, PHP ou encore Erlang, un mini serveur Web prêt à l'emploi

La version 2022.1 d'IntelliJ IDEA va prendre en charge les fonctionnalités de Java 18 : un aperçu des mises à jour pour le langage

Les contrôleurs de conformité d'Oracle incluraient désormais Java dans les audits de licence, les abonnements payants introduits il y a trois ans retiennent désormais l'attention de l'équipe

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de thelvin
Modérateur https://www.developpez.com
Le 30/07/2022 à 3:32
Citation Envoyé par 23JFK Voir le message
C'est quoi cette idée à la con de casser la portabilité en privilégiant l'encodage système sur UTF-8 ?
L'idée c'est que depuis Java 18, on a arrêté d'avoir un "charset par défaut" dans Java qui dépende de la machine sur laquelle on fait tourner le programme.

Ça fait maintenant un certain temps qu'il est moins souvent utile pour un programme, de s'adapter à la machine en cours, que de simplement faire comme tout le monde et d'utiliser utf-8.

Du coup, depuis Java 18, le charset par défaut c'est utf-8 et puis c'est tout. Peu importe la machine. On peut en définir un autre avec des options de démarrage, mais si on fait rien contre, désormais le charset par défaut c'est utf-8. Pour la plupart des usages, c'est très bien, ça unifie le comportement de Java quelle que soit la machine sur laquelle on programme, et ça évite d'encourager des bugs.

Par contre il y a un truc nase, c'est que sous windows, les consoles n'utilisent pas l'encodage utf-8. Or l'encodage pour écrire dans la console, c'était l'encodage par défaut (ce qui ne marchait d'ailleurs pas bien, parce que sous Windows, les consoles n'utilisent pas le même charset que le reste du système. N'empêche, c'était comme ça.) De ce fait, il a été décidé que changer le charset par défaut alors que sur les consoles Windows il y a peu de chances que ce soit le bon, c'était pas top et donc pour le cas précis de System.out et System.err, le charset utilisé reste le même qu'avant Java 18. Un nouveau réglage de charset est inventé, seulement pour System.out et System.err.

Comme ça si les gens avaient reconfiguré leurs consoles pour afficher les accents des programmes Java, ça continuerait de marcher tout pareil.

Sauf que :

- il y en a qui utilisent des consoles "moins communes" qui utilisent bel et bien l'encodage utf-8. Du coup pour ce cas c'était pas une bonne idée d'empêcher l'usage d'utf-8, donc on fournit un moyen de l'utiliser.
- ceux qui essayaient d'afficher correctement les accents des programmes Java dans la console, ils ne configuraient pas la console. Ils programmaient leur programme Java pour utiliser le charset de la console. Une méthode (assez mauvaise) de faire ça est de démarrer le programme Java avec comme charset par défaut, celui de la console. Ça marchait mais ça change le charset par défaut de tout le programme juste pour gérer la console. Mais donc, depuis Java 18, ce système est cassé puisque System.out et System.err n'utilisent plus le charset par défaut. D'où le besoin d'un réglage qui permette de refaire un truc de ce genre comme avant. Ce ne sera probablement pas utilisé pour faire de l'utf-8, mais autre chose. Peu importe, on a un exemple de comment s'en servir.
3  0 
Avatar de OButterlin
Modérateur https://www.developpez.com
Le 30/07/2022 à 16:29
Citation Envoyé par 23JFK Voir le message
Faut quand même vouloir se faire mal pour utiliser System.out dans une console windows.
Non, pas du tout, ça dépend du type de programme qu'on développe.
Par exemple, j'ai développé une API pour intégrer des fichiers csv / xls(x) / reqûetes SQL etc, la sortie System.out est très utile pour tracer l'activité des processeurs d'intégration, et ça permet au système de planification des travaux de récupérer une log utile en cas de problème.

Bien sûr, je n'utilise pas ça dans une application web ou dans un EJB métier...
2  0 
Avatar de 23JFK
Inactif https://www.developpez.com
Le 29/07/2022 à 20:00
C'est quoi cette idée à la con de casser la portabilité en privilégiant l'encodage système sur UTF-8 ?
3  2 
Avatar de thelvin
Modérateur https://www.developpez.com
Le 04/12/2022 à 17:06
Ben oui mais alors tu fais des reproches à Java que tu ne fais jamais à rien d'autre.

Tous les systèmes fonctionnent comme ça, avec ces effets, depuis que tu existes. Mais maintenant c'est Java ta tête de turc.

Tu reproches littéralement à Java de ne pas être resté à la version que tu t'es mis à utiliser à un moment, puisque par définition de nouvelles versions ça veut dire des changements, et que par définition un changement fait qu'un truc qui comptait sur le fait que ce soit pas comme ça, se met à ne plus marcher. Ça signifie qu'aucun effort de compatibilité ascendante n'est parfait, comme notamment ça n'a jamais été particulièrement bon dans aucune chose que tu aies jamais utilisée. Et pourtant ce n'est pas à tout le reste que tu fais des reproches.

Et sinon, si quelque chose ne marche pas en changeant la version "canonique" de Java installée sur un système, il suffit de ne pas la changer en installant d'autres versions. Rien de malsain là-dedans.
1  0 
Avatar de smillien62
Futur Membre du Club https://www.developpez.com
Le 15/11/2022 à 12:21
Pour basculer la console Windows en UTF-8 :
chcp 65001
0  0 
Avatar de grunt2000
Membre éclairé https://www.developpez.com
Le 01/12/2022 à 19:35
Les amis, mais connaissez-vous une entreprise qui utilise java 17 en production ?
Si c'est le cas, c'est à l'unité. Rien n'est compatible avec lui, et de loin :
chaque ligne commande pour lancer un traitement existant s'agrémente de

Code : Sélectionner tout
1
2
3
4
5
6
java --add-exports java.base/sun.nio.ch=ALL-UNNAMED \
   --add-opens java.base/java.util=ALL-UNNAMED \
   --add-opens java.base/java.nio=ALL-UNNAMED \
   --add-opens java.base/java.lang=ALL-UNNAMED \
   --add-opens java.base/java.lang.invoke=ALL-UNNAMED \
   -jar leProgramme.jar
Alors, Java 19, quand il y a zéro utilisateurs de Java 17... À quoi bon...
Depuis le flop des modules, les choix sont discutables.
0  0 
Avatar de thelvin
Modérateur https://www.developpez.com
Le 02/12/2022 à 5:52
Hello,

on est pas encore en prod mais on utilise Java 17 pour nos versions en cours de release, et on a pas détecté de problème de ce genre-là.
C'est pas en prod, mais c'est en dev, QA, staging et on attaque la pré-prod lundi.

On notera :

- que nous on n'utilise pas les modules, du coup oui c'est pas surprenant qu'on ait pas ce problème-là.
- que des bibliothèques populaires de l'écosystème Java qui comptent comme module sans nom, il en reste plus franchement des quantités. (Au boulot on utilise pas les modules, mais je le fais à titre perso et elles ont toutes un nom.)
- qu'on est pas censé utiliser les classes fournies par la JVM en dehors des packages java et javax. Et que ça fait plus de 15 ans que tout le monde s'en passe sans problème.
0  0 
Avatar de grunt2000
Membre éclairé https://www.developpez.com
Le 02/12/2022 à 22:22
Je vois ça avec les exécutables existants que j'ai à droite et à gauche dans l'entreprise.

Je ne peux pas dire chacun de quels dépendances ils sont faits qui amènent quels problèmes, parce qu'avec les dépendances, par Maven, l'une tire l'autre et une application peut rassembler souvent 20 à 50 jars.
Simplement, constater qu'ils ne se lancent pas du premier coup, sans réglages.

Il y a peu, j'essayais Spark et Zeppelin : eh bien, aucun ne passe en Java 17. Java 17 n'assure pas la compatibilité ascendante. En tous cas, pas instantanément : il faut faire des réglages pour avoir un fonctionnement correct, ce qui implique d'avoir la capacité d'intervenir sur toutes les applications : retrouver leurs .sh de lancement, pour les adapter. Faut avoir le temps et l'envie.

Le problème, c'est pas de passer un programme en Java 17.
Mais que tous les programmes qui sont sur son PC ou serveur le supportent : parce que c'est rare (et pas sain) les machines avec deux JDK ou Java de versions différentes qui fonctionnent conjointement. Donc on préfère migrer un bon coup.
Et là, c'est vraiment pas parti pour. Java 17 m'a l'air d'être un flop, ce qui m'interroge sur la suite de Java. Java 19 ? À quoi bon ? Si personne n'est sur le 17 ?
0  0 
Avatar de thelvin
Modérateur https://www.developpez.com
Le 03/12/2022 à 15:52
Oui ben dans les faits il y a beaucoup d'environnements d'accord avec toi et beaucoup qui ne le sont pas. Notamment parce qu'un certain nombre d'outils ne sont pas en Java, et que ceux qui le sont, c'est bien de dire "on a pas envie de toucher" mais il y a ce truc qui s'appelle "sécurité" et donc si tu touches pas à un truc pendant plus d'un an, c'est que tu te dis que quiconque s'en sert devrait se faire pirater plus souvent.

Au passage soyons précis : Java 17 assure très bien la compatibilité ascendante. C'est Java 9 qui ne l'assure pas top, et très très mal si on utilise les modules. Dans la mesure où Java 9 n'est pas à support longue durée, on peut dire alors que c'est Java 11. Aucune difficulté pour passer de Java 11 à une version plus tardive.

Au passage également, s'il y a mention de java.base/sun.nio.ch ce n'est pas Java qui n'a pas assuré la compatibilité, c'est l'auteur. Il savait très bien que les chances de compatibilité ascendantes seraient réduites et si elles marchent ce ne serait que par chance, et il a décidé que c'est ce qu'il voulait. A ce niveau-là, corriger les failles de sécurité c'est casser la compatibilité. Et si moi je voulais que ce vecteur d'attaque fonctionne sur mon environnement, hein ?

Mais que tous les programmes qui sont sur son PC ou serveur le supportent : parce que c'est rare (et pas sain) les machines avec deux JDK ou Java de versions différentes qui fonctionnent conjointement.
Ça m'a tout l'air d'un culte cargo. Qui dit ça et pourquoi ?
0  0 
Avatar de 23JFK
Inactif https://www.developpez.com
Le 30/07/2022 à 5:05
Faut quand même vouloir se faire mal pour utiliser System.out dans une console windows.
1  2