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

211

Les problèmes de jeux de caractères sont déroutants et compliqués en eux-mêmes, mais en plus de cela, vous devez vous souvenir des noms exacts de vos jeux de caractères. C'est ça "utf8"? Ou "utf-8"? Ou peut "UTF-8"- être ? 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 les utiliser Charset.UTF8?

serg
la source
19
+1: Cela me dérangeait aussi tout le temps. Soit dit en passant, la même histoire se poursuit MessageDigest#getInstance().
BalusC
2
Pour la vraie réponse, vous devez demander à quelqu'un chez Sun. Bonne chance avec ça :-)
Stephen C
1
Stephen C: Je crois que cela a été discuté sur une liste de diffusion publique. -Quelqu'un au soleil.
Tom Hawtin - tackline
1
voir cette question
yegor256

Réponses:

160

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

Cependant, il y en a six qui doivent être présents, donc des constantes auraient pu être faites depuis longtemps. Je ne sais pas pourquoi ils ne l'étaient pas.

JDK 1.4 a fait une grande chose en introduisant le type Charset. À ce stade, ils n'auraient plus voulu fournir de constantes String, car l'objectif est d'amener tout le monde à utiliser les instances de Charset. Alors pourquoi ne pas fournir les six constantes Charset standard? J'ai demandé à Martin Buchholz car il se trouve juste à côté de moi, et il a dit qu'il n'y avait pas vraiment de bonne raison, sauf qu'à l'époque, les choses étaient encore à moitié cuites - trop peu d'API JDK avaient été modernisées pour accepter Charset, et parmi ceux qui l'étaient, les surcharges de Charset se sont généralement comportées légèrement moins bien.

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

Pour faire court - définissez simplement vos propres constantes, ou utilisez la classe Charsets de Guava à laquelle Tony le Poney était lié (bien que cette bibliothèque ne soit pas encore réellement publiée).

Mise à jour: une StandardCharsetsclasse est en JDK 7.

Kevin Bourrillion
la source
Juste curieux, une idée quand il y aura une sortie (alpha / beta / quoi que ce soit) de Guava? La page d'accueil du projet est un peu brève à ce sujet.
Jonik
Pas de dinde pour moi jusqu'à ce qu'il soit sorti!
Kevin Bourrillion
la raison pour laquelle c'est incroyablement bizarre et je ne peux pas l'expliquer, mais est liée à la sécurité - vous pouvez créer une chaîne modifiable via des jeux de caractères personnalisés, mais ils auraient pu être rendus plus rapides que la chaîne (qui recherche en fait le jeu de caractères). C'est une omission / négligence de la façon dont String(byte bytes[], int offset, int length, Charset charset)est mis en œuvre. En fait, la performance atteinte n'est pas du tout triviale lors de la création d'une petite chaîne à partir d'un grand octet [].
bestsss
7
Pas juste! Vous avez accès à de telles ressources. = (J'ai vu une autre réponse où vous avez dit un jour: "Ouais, alors j'ai demandé à Josh [Bloch] à ce sujet ..."
kevinarpe
PrintStream ne prend pas en charge Charset
rofrol
102

Deux ans plus tard, et Java 7 de les StandardCharsets définit maintenant des 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.

Etienne Neveu
la source
29

Je dirais que nous pouvons faire beaucoup mieux que cela ... pourquoi les jeux de caractères dont la disponibilité est garantie ne sont-ils pas directement accessibles? Charset.UTF8devrait être une référence à la Charset, pas le nom sous forme de chaîne. De cette façon, nous n'aurions pas à gérer UnsupportedEncodingExceptionpartout.

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

Revenons à propos de la prise en charge des jeux de caractères Java - pourquoi n'y a-t-il pas de constructeur pour FileWriter/ FileReaderqui prend un Charset? Fondamentalement, ce sont des classes presque inutiles en raison de cette restriction - vous avez presque toujours besoin d'un InputStreamReaderautour d'un FileInputStreamou de l'équivalent pour la sortie :(

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

EDIT: Il me vient à l'esprit que cela n'a pas vraiment répondu à la question. La vraie réponse est vraisemblablement soit "personne impliqué n'y a pensé" ou "quelqu'un impliqué a pensé que c'était une mauvaise idée". Je suggérerais fortement que les classes 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 que depuis Java 7, vous utiliseriez simplement à la StandardCharsetsplace.)

Jon Skeet
la source
2
+1. Mais en tant que méthode plutôt que champ afin de permettre le chargement paresseux (d'accord, vous allez probablement vouloir UTF-8, mais il y a quelques autres jeux de caractères et vous voudrez peut-être des installations similaires pour eux). Malheureusement, cela ne semble pas être très populaire auprès de ceux qui prennent les décisions.
Tom Hawtin - tackline
Je serais assez heureux avec une méthode, bien que j'espère que charger ces quelques jeux de caractères avec impatience ne serait pas un coût important.
Jon Skeet
1
Nous sommes en croisade pour arrêter le chargement impatient des classes. / Je viens de faire une recherche d'un JDK pour "UTF-8". 270 correspondance (s) trouvée (s) dans 165 fichier (s). Bien que beaucoup de cela se trouve dans de vieilles ordures Apache (je pense que cela a été apporté par mon équipe).
Tom Hawtin - tackline
1
@tackline: Je suppose que le chargement de classe avide est l'une de ces choses qui monte avec le temps. Quelques cours ici, quelques cours là-bas - chacun sonnant individuellement assez inoffensif - pourraient faire une grande différence.
Jon Skeet
Le dernier lien, à Guava Charsets, est rompu.
LarsH
28

Dans Java 1.7

import java.nio.charset.StandardCharsets

ex: StandardCharsets.UTF_8 StandardCharsets.US_ASCII

Roger
la source
5

L'état actuel de l'API d'encodage laisse à désirer. Certaines parties de l'API Java 6 n'acceptent Charseten place d'une chaîne (en logging, dom.ls, PrintStream, il peut y 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 sont arrivées là où elles sont; Je ne suis pas sûr d'avoir des idées brillantes sur la façon de les corriger.


En aparté...

Vous pouvez rechercher les noms de l'implémentation de Java 6 de Sun ici .

Pour UTF-8, les valeurs canoniques sont "UTF-8"pour java.nioet "UTF8"pour java.langet java.io. Les seuls encodages que la spécification nécessite un JRE pour prendre en charge sont: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16 .

McDowell
la source
2
Je ne regrette pas celle de PrintStream, car la classe dit clairement "La classe PrintWriter devrait être utilisée dans des situations qui nécessitent d'écrire des caractères plutôt que des octets." (Ce qui est, comme, toutes les situations ...)
Kevin Bourrillion
2

J'ai défini il y a longtemps une classe utilitaire avec les constantes UTF_8, ISO_8859_1 et US_ASCII Charset.

En outre, il y a quelque temps longtemps (2 ans et plus ) je l' ai fait un simple test de performance entre new String( byte[], Charset )et new String( byte[], String charset_name )et a découvert que cette dernière mise en œuvre est FORTEMENT plus rapide. Si vous jetez un œil sous le capot au code source, vous verrez qu'ils suivent en effet 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.

Alexander Pogrebnyak
la source
1
Le Charsetbesoin n'a pas besoin d'être enregistré, donc l'exception peut se produire. IIRC, il y a eu quelques changements dans JDK7 pour le rendre plus rapide pour les Charsetimplémentations connues (éliminer la copie supplémentaire).
Tom Hawtin - tackline