Perché i nomi dei set di caratteri non sono costanti?


211

I problemi dei set di caratteri sono confusi e complicati da soli, ma soprattutto devi ricordare i nomi esatti dei tuoi set di caratteri. È vero "utf8"? Oppure "utf-8"? O forse "UTF-8"? Durante la ricerca di esempi di codice in Internet vedrai tutto quanto sopra. Perché non solo farli nominare costanti e usarli Charset.UTF8?


19
+1: Anche questo mi dava fastidio. La stessa storia continua comunque MessageDigest#getInstance().
BalusC,

2
Per la vera risposta, dovresti chiedere a qualcuno di Sun. Buona fortuna con questo :-)
Stephen C

1
Stephen C: Credo che sia stato discusso in una mailing list pubblica. -Qualcuno al sole.
Tom Hawtin - affronta il

Risposte:


160

La semplice risposta alla domanda è che le stringhe di set di caratteri disponibili variano da piattaforma a piattaforma.

Tuttavia, ci sono sei che devono essere presenti, quindi le costanti avrebbero potuto essere fatte per quelli molto tempo fa. Non so perché non lo fossero.

JDK 1.4 ha fatto una grande cosa introducendo il tipo Charset. A questo punto, non avrebbero più voluto fornire costanti di stringa, poiché l'obiettivo è far sì che tutti utilizzino le istanze di Charset. Quindi perché non fornire le sei costanti Charset standard, quindi? Ho chiesto a Martin Buchholz poiché è seduto proprio accanto a me, e mi ha detto che non c'era un motivo davvero eccezionale, tranne per il fatto che all'epoca le cose erano ancora cotte a metà - troppo poche API JDK erano state adattate accetta Charset, e di quelli che erano, i sovraccarichi di Charset di solito andavano leggermente peggio.

È triste che solo in JDK 1.6 abbiano finalmente finito di attrezzare tutto con i sovraccarichi di Charset. E che questa situazione di prestazioni all'indietro esiste ancora (il motivo per cui è incredibilmente strano e non posso spiegarlo, ma è legato alla sicurezza!).

Per farla breve: basta definire le proprie costanti o utilizzare la classe Charsets di Guava a cui Tony the Pony collegava (anche se quella libreria non è ancora stata rilasciata).

Aggiornamento: una StandardCharsetsclasse è in JDK 7.


Solo curioso, qualche idea su quando ci sarà un rilascio (alfa / beta / qualunque cosa) di Guava? La homepage del progetto è un po 'bruta su questo.
Jonik,

Nessun tacchino per me fino a quando non sarà fuori!
Kevin Bourrillion,

il motivo per cui è incredibilmente strano e non posso spiegarlo, ma è legato alla sicurezza : puoi creare una stringa modificabile tramite set di caratteri personalizzati, ma avrebbero potuto essere fatti funzionare anche più velocemente della stringa (che in realtà cerca il set di caratteri). È un'omissione / negligenza come String(byte bytes[], int offset, int length, Charset charset)viene implementata. In effetti, l'hit di performance non è affatto banale quando si crea una stringa piccola da un byte grande [].
bestsss

7
No giusto! Hai accesso a risorse così grandi. = (Ho visto un'altra risposta in cui una volta hai detto: "Sì, quindi ho chiesto a Josh [Bloch] di questo ..."
kevinarpe,

PrintStream non supporta Charset
rofrol

102

Due anni dopo, e StandardCharsets di Java 7 ora definisce le costanti per i 6 set di caratteri standard.

Se sei bloccato su Java 5/6, puoi usare le costanti Charsets di Guava , come suggerito da Kevin Bourrillion e Jon Skeet.


29

Direi che possiamo fare molto meglio di così ... perché i set di caratteri garantiti per essere disponibili sono accessibili direttamente? Charset.UTF8dovrebbe essere un riferimento a Charset, non il nome come stringa. In questo modo non dovremmo gestireUnsupportedEncodingException tutto il posto.

Intendiamoci, penso anche che .NET abbia scelto una strategia migliore in modo predefinito su UTF-8 ovunque. Quindi ha rovinato nominando semplicemente la proprietà di codifica "default del sistema operativo" Encoding.Default- che non lo è il valore predefinito all'interno di .NET stesso :(

Tornando al ranting sul supporto del set di caratteri Java - perché non esiste un costruttore per FileWriter/ FileReaderche richiede un Charset? Fondamentalmente quelle sono classi quasi inutili a causa di quella restrizione - quasi sempre hai bisogno di un InputStreamReadergiro aFileInputStream o all'equivalente per l'output :(

Infermiera, infermiera - dov'è la mia medicina?

EDIT: Mi viene in mente che questo non ha veramente risposto alla domanda. La vera risposta è presumibilmente o "nessuno coinvolto ci pensava" o "qualcuno coinvolto pensava che fosse una cattiva idea". Suggerirei vivamente che le classi di utilità interne che forniscono i nomi o i set di caratteri evitino la duplicazione attorno alla base di codice ... O potresti semplicemente usare quello che abbiamo usato su Google quando questa risposta è stata scritta per la prima volta . (Nota che a partire da Java 7, StandardCharsetsinvece , useresti semplicemente .)


2
+1. Ma come metodo piuttosto che come campo in modo da consentire il caricamento lento (va bene, probabilmente vorrai UTF-8, ma ci sono alcuni altri set di caratteri e potresti desiderare strutture simili per loro). Purtroppo questo non sembra essere molto popolare tra coloro che prendono le decisioni.
Tom Hawtin - tackline

Sarei abbastanza felice con un metodo, anche se spero che caricare avidamente quei pochissimi set di caratteri non sia un costo significativo.
Jon Skeet,

1
Siamo su una crociata per fermare il carico di classe desideroso. / Ho appena cercato un JDK per "UTF-8". Trovate 270 corrispondenze in 165 file. Anche se molto è nella vecchia spazzatura di Apache (credo che abbia contribuito con il mio team).
Tom Hawtin - tackline

1
@tackline: Suppongo che il caricamento di classe desideroso sia una di quelle cose che si monta nel tempo. Alcune lezioni qui, alcune lezioni lì - ognuna che suona individualmente abbastanza innocua - potrebbero fare una grande differenza.
Jon Skeet,

L'ultimo collegamento, a Guava Charsets, è interrotto.
LarsH

28

In Java 1.7

import java.nio.charset.StandardCharsets

ex: StandardCharsets.UTF_8 StandardCharsets.US_ASCII


5

Lo stato corrente dell'API di codifica lascia a desiderare. Alcune parti del Java 6 API non accettano Charsetin luogo di una stringa (in logging, dom.ls, PrintStream, ci possono essere altri). Non aiuta il fatto che le codifiche dovrebbero avere nomi canonici diversi per le diverse parti della libreria standard.

Posso capire come le cose sono arrivate dove sono; non sono sicuro di avere idee geniali su come risolverli.


A parte ...

Puoi cercare i nomi per l'implementazione Java 6 di Sun qui .

Per UTF-8, i valori canonici sono "UTF-8"per java.nioe "UTF8"per java.lange java.io. Le uniche codifiche che la specifica richiede un JRE per supportare sono: US-ASCII; ISO-8859-1; UTF-8; UTF-16 BE; UTF-16; UTF-16 .


2
Non mi rammarico per quello di PrintStream, poiché la classe dice chiaramente "La classe PrintWriter dovrebbe essere usata in situazioni che richiedono la scrittura di caratteri anziché di byte". (Che è, come, tutte le situazioni ...)
Kevin Bourrillion,

2

Molto tempo fa ho definito una classe di utilità con costanti Charset UTF_8, ISO_8859_1 e US_ASCII.

Inoltre, molto tempo fa (più di 2 anni) ho fatto un semplice test delle prestazioni tra new String( byte[], Charset )e ho new String( byte[], String charset_name )scoperto che quest'ultima implementazione è CONSIDERABILE più veloce. Se dai un'occhiata sotto il cofano al codice sorgente vedrai che effettivamente seguono un percorso piuttosto diverso.

Per questo motivo ho incluso un'utilità nella stessa classe

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

Perché il costruttore String (byte [], Charset) non fa lo stesso, mi batte.


1
Non è Charsetnecessario registrarsi, quindi può verificarsi un'eccezione. IIRC, ci sono stati alcuni cambiamenti nel JDK7 per renderlo più veloce per Charsetimplementazioni note (eliminare la copia extra).
Tom Hawtin - affronta il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.