web-dev-qa-db-fra.com

Pourquoi les noms de jeux de caractères ne sont pas des constantes?

Les problèmes de jeu de caractères sont déroutants et compliqués en eux-mêmes, mais vous devez en plus vous rappeler les noms exacts de vos jeux de caractères. Est-ce "utf8"? Ou "utf-8"? Ou peut-être "UTF-8"? Lorsque vous recherchez des exemples de code sur Internet, vous verrez tout ce qui précède. Pourquoi ne pas simplement leur faire des constantes nommées et utiliser Charset.UTF8?

208
serg

La réponse simple à la question posée est que les chaînes de jeux de caractères disponibles varient d'une plateforme à l'autre.

Cependant, il en faut six, donc des constantes auraient pu être faites pour celles d’il ya longtemps. Je ne sais pas pourquoi ils ne l'étaient pas.

JDK 1.4 a fait une bonne chose en introduisant le type Charset. À ce stade, ils n'auraient plus voulu fournir de constantes String, car l'objectif est que tout le monde utilise des instances Charset. Alors, pourquoi ne pas fournir les six constantes de Charset standard? J'ai demandé à Martin Buchholz puisqu'il se trouvait juste à côté de moi et il m'a répondu qu'il n'y avait pas vraiment de raison particulière, sauf qu'à l'époque, les choses étaient encore à moitié cuites - trop peu d'API JDK avaient été modernisées. accepter Charset, et parmi ceux qui l’ont été, les surcharges de Charset ont généralement été légèrement pires.

Il est regrettable que ce ne soit que dans JDK 1.6 qu'ils aient enfin fini de tout équiper avec des surcharges de Charset. Et que cette situation de performance en arrière existe toujours (la raison pour laquelle c'est incroyablement étrange et je ne peux pas l'expliquer, mais c'est lié à la sécurité!).

Long story story - définissez simplement vos propres constantes ou utilisez la classe Charsets de Guava à laquelle Tony the Pony est lié (bien que cette bibliothèque ne soit pas encore réellement publiée).

Mise à jour: a StandardCharsets la classe est dans JDK 7.

157

Deux ans plus tard, et Java 7 StandardCharsets) définit maintenant les constantes pour les 6 jeux de caractères standard.

Si vous êtes bloqué sur Java 5/6, vous pouvez utiliser les constantes Charsets de Guava, comme suggéré par Kevin Bourrillion et Jon Skeet.

101
Etienne Neveu

Je dirais que nous pouvons faire beaucoup mieux que cela ... pourquoi les jeux de caractères garantis-disponibles ne sont-ils pas accessibles directement? Charset.UTF8 devrait être une référence à Charset, pas le nom sous forme de chaîne. De cette façon, nous n'aurions pas à gérer UnsupportedEncodingException partout.

Remarquez, je pense aussi que .NET a choisi une meilleure stratégie en passant par défaut à UTF-8 partout. Il a ensuite bousillé en nommant la propriété de codage "système d'exploitation par défaut" simplement Encoding.Default - qui n'est pas la valeur par défaut dans .NET lui-même :(

Revenons à la discussion sur le support des jeux de caractères sous Java - pourquoi n’existe-t-il pas de constructeur pour FileWriter/FileReader qui prend un Charset? En gros, ce sont des classes presque inutiles à cause de cette restriction - vous avez presque toujours besoin d'un InputStreamReader autour d'un FileInputStream ou de l'équivalent pour la sortie :(

Infirmière, infirmière - où est mon médicament?

EDIT: Il me semble que cela n’a pas vraiment répondu à la question. La vraie réponse est vraisemblablement soit "personne n'y a pensé que ce soit", soit "quelqu'un a pensé que c'était une mauvaise idée". Je suggérerais fortement que les classes d'utilitaires internes fournissant les noms ou les jeux de caractères évitent la duplication autour de la base de code ... Ou vous pouvez simplement utiliser celui que nous avons utilisé chez Google lorsque cette réponse a été écrite pour la première fois . (Notez qu'à partir de Java 7, vous utiliseriez simplement StandardCharsets à la place.)

29
Jon Skeet

Dans Java 1.7

import Java.nio.charset.StandardCharsets

ex: StandardCharsets.UTF_8StandardCharsets.US_ASCII

27
Roger

L'état actuel de l'API de codage laisse à désirer. Certaines parties de l'API Java 6) n'acceptent pas Charset à la place d'une chaîne (dans logging, dom.ls, PrintStream; il peut y en avoir d'autres). Cela n'aide pas que les encodages soient supposés avoir des noms canoniques différents pour différentes parties de la bibliothèque standard.

Je peux comprendre comment les choses se sont passées là où elles sont. Je ne suis pas sûr d'avoir des idées brillantes sur la façon de les réparer.


En aparté...

Vous pouvez rechercher les noms de Sun Java 6 implementation ici .

Pour UTF-8, les valeurs canoniques sont "UTF-8" pour Java.nio et "UTF8" pour Java.lang et Java.io. Les seuls encodages que la spécification nécessite la prise en charge d'un JRE sont les suivants: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16 .

5
McDowell

J'ai depuis longtemps défini une classe d'utilitaires avec les constantes UTF_8, ISO_8859_1 et US_ASCII Charset.

De plus, il y a longtemps (2 ans et plus), j'ai fait un test de performance simple entre new String( byte[], Charset ) et new String( byte[], String charset_name ) et j'ai découvert que cette dernière implémentation est CONSIDÉRABLEMENT plus vite. Si vous jetez un coup d'œil sous le capot du code source, vous verrez qu'il suit un chemin tout à fait différent.

Pour cette raison, j'ai inclus un utilitaire dans la même classe

public static String stringFromByteArray (
    final byte[] array,
    final Charset charset
)
{
    try
    {
        return new String( array, charset.name( ) )
    }
    catch ( UnsupportedEncodingException ex )
    {
        // cannot happen
    }
}

Pourquoi le constructeur String (byte [], Charset) ne fait pas la même chose, me bat.

2