JEP 400, UTF-8 par défaut
Contexte
L’encodage par défaut était calculé au démarrage en fonction du système d’exploitation, les paramètres régionaux de l’utilisateur ou d’autres facteurs.
En effet, qui n’a jamais eu ce type de caractère à l’écran ou dans ces fichiers ? :
UTF-8 par défaut
La solution généralement était de préciser la propriété -Dfile.encoding=…
. Cela permet de fixer l’encodage par défaut.
L’objectif est de faire en sorte que UTF-8
soit l’encodage par défaut quelque soit le système.
Cela permet de simplifier, d’améliorer la portabilité et notamment la cohérence de la plateforme.
Le choix
Le choix du jeu de caractère UTF-8
fut logique. C’est encodage le plus utilisé sur le web (97,7% à ce jour). C’est aussi un encodage standard au niveau de XML et JSON. Java l’utilise déjà par défaut pour l’API NIO.
A partir du JDK 18, la JVM prendra l’encodage UTF-8 par défaut. Nous pouvons le vérifier avec jshell
jshell> java.nio.charset.Charset.defaultCharset()
$4 ==> UTF-8
Pensez à importer le package java.nio.charset
afin de pouvoir manipuler directement la classe Charset
.
Pour bien comprendre, nous configurons notre système pour utiliser l’encodage ISO-8859-15. Pour vérifier, nous utilisons la commande locale
.
LANG=fr_FR@euro
...
Ainsi, avec un JDK 17, nous obtenons
jshell> Charset.defaultCharset()
$4 ==> ISO-8859-15
Alors qu’avec un JDK 18, nous obtenons toujours UTF-8
jshell> Charset.defaultCharset()
$4 ==> UTF-8
Si nous lançons un JDK 17 en précisant la propriété file.encoding="UTF-8"
, nous obtenons bien l’encodage UTF-8 bien que notre système est en ISO-8859-15.
jshell> Charset.defaultCharset()
$4 ==> UTF-8
Passage de propriété pour jshell
Pour les tests, nous sommes amenés à devoir modifier les propriétés de la JVM.
Pour passer une propriété avec jshell, il faut utiliser l’option -R. Nous obtenons la ligne de commande suivante :
/../jdk-xy/bin/jshell -R-Dfile.encoding="UTF-8"
Préparation
Cela était en préparation depuis quelques temps.
Nouvelle propriété
Le JDK 17 a introduit une nouvelle propriété native.encoding
. Cette propriété permet de connaitre l’encodage du système hôte. Nous comprenons d’autant plus l’intérêt de cette propriété maintenant.
Au delà de cette propriété, il est à noter que les consoles standard ou d’erreurs restent avec l’encodage natif.
Et le JDK 18 apporte une nouvelle méthode charset()
sur la classe PrintStream
pour connaitre directement l’encodage utilisé.
Cela permet d’en tenir compte au niveau des flux.
jshell> System.out.charset()
$5 ==> ISO-8859-15
jshell> System.err.charset();
$6 ==> ISO-8859-15
Fichier de propriétés
Pour rappel, c’est seulement à partir du JDK 9 que les fichiers de propriétés sont au format UTF-8 via la JEP 226: UTF-8 Property Resource Bundles
Cohérence de la plateforme
Je vous parlais de cohérence de la plateforme. Il faut effectivement savoir que les API n’étaient pas uniformes pour les valeurs par défaut.
Prenons l’exemple de la classe java.io.FileWriter
avec deux constructeurs :
-
FileWriter(File file)
-
FileWriter(File file, Charset charset)
Le premier constructeur dépend du jeu de caractère par défaut Charset.defaultCharset()
. Donc ce dernier dépendait du système et de la configuration du système.
En revanche, si je prends la classe java.nio.Files
avec les méthodes lines
:
-
Files.lines(Path path)
-
Files.lines(Path path, Charset charset)
Cette fois, la méthode lit le fichier avec l’encodage UTF-8. Cela est le cas pour l’ensemble des méthodes de la classe Files
et de l’api NIO.
Maintenant, c’est plus simple, toutes les API sont en UTF-8 par défaut.
Compatibilité
La compatibilité reste un point fort de Java et une des préoccupations majeures lors des changements. L’équipe a prévu de garder la compatibilité avec l’ancien mode de calcul de l’encodage. Pour cela, il faut mettre à la valeur COMPAT à la propriété file.encoding
Voici le résultat sur un système Linux où la locale est toujours à ISO-8859-15.
/../jdk-xy/bin/jshell -R-Dfile.encoding="COMPAT"
Welcome to JShell -- Version 18-ea
| For an introduction type: /help intro
jshell> System.getProperty("file.encoding")
$1 ==> "ISO-8859-15"
Vérification
Si vous êtes concerné par le changement d’encodage, vous pouvez tester simplement l’impact en utilisant la propriété file.encoding
=UTF-8
. Cela donne la commande suivante
/../jdk-[8-17]/bin/java -Dfile.encoding=UTF-8 ....
Il est à noter que vous pouvez le faire tout de suite avec votre JDK.
Compilation
Parlons de compilation, mais pourquoi ?
Tout simplement parce que le compilateur Javac est aussi concerné. Ce dernier va lire et écrire les fichiers en UTF-8.
De la même manière, vous pouvez vous assurer d’ores et déjà du bon fonctionnement en précisant la propriété file.encoding
.
/../jdk-[8-17]/bin/javac -Dfile.encoding=UTF-8 ....
Bien que je ne le conseille pas. Puisque les sources sont en UTF-8, il est possible d’utiliser des accents si nous le souhaitons.
class Hello {
public static void main(String[] args) {
String téléphone = "01.02.03.04.05";
System.out.println("Tél : " + téléphone);
}
}
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne
Billets récents
- Eclipse plante systématiquement sous Debian (et autres distribution Linux)
- JEP 463, Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Debian - Montée de version de Debian 11 (Bullseye) à Debian 12 (Bookworm)
- JEP 451, Prepare to Disallow the Dynamic Loading of Agents
- JEP 444, Virtual Threads