¿Por qué los nombres de caracteres no son constantes?

211

Los problemas de juego de caracteres son confusos y complicados por sí mismos, pero además de eso, debe recordar los nombres exactos de sus juegos de caracteres. Es "utf8"? O "utf-8"? O tal vez "UTF-8"? Al buscar ejemplos de código en Internet, verá todo lo anterior. ¿Por qué no simplemente hacer que sean constantes con nombre y uso Charset.UTF8?

serg
fuente
19
+1: Esto también me estaba molestando todo el tiempo. La misma historia continúa MessageDigest#getInstance()por cierto.
BalusC el
2
Para la respuesta real, deberías preguntarle a alguien en Sun. Buena suerte con eso :-)
Stephen C
1
Stephen C: Creo que se ha discutido en una lista de correo pública. -Alguien en Sun.
Tom Hawtin - tackline el
1
ver esta pregunta
yegor256

Respuestas:

160

La respuesta simple a la pregunta es que las cadenas de caracteres disponibles varían de una plataforma a otra.

Sin embargo, hay seis que deben estar presentes, por lo que se podrían haber hecho constantes para aquellos hace mucho tiempo. No sé por qué no lo fueron.

JDK 1.4 hizo una gran cosa al introducir el tipo Charset. En este punto, ya no habrían querido proporcionar constantes de cadena, ya que el objetivo es hacer que todos usen instancias de Charset. Entonces, ¿por qué no proporcionar las seis constantes Charset estándar? Le pregunté a Martin Buchholz porque estaba sentado a mi lado, y dijo que no había una razón realmente especial, excepto que en ese momento, las cosas todavía estaban a medias: muy pocas API JDK habían sido adaptadas para aceptar Charset, y de los que eran, las sobrecargas de Charset generalmente tuvieron un rendimiento ligeramente peor.

Es triste que solo sea en JDK 1.6 que finalmente terminaron de equipar todo con sobrecargas de Charset. Y que esta situación de rendimiento hacia atrás todavía existe (la razón por la cual es increíblemente extraña y no puedo explicarlo, ¡pero está relacionada con la seguridad!).

Larga historia corta: solo defina sus propias constantes o use la clase Charsets de Guava a la que Tony the Pony se vinculó (aunque esa biblioteca aún no se ha lanzado realmente).

Actualización: una StandardCharsetsclase está en JDK 7.

Kevin Bourrillion
fuente
Solo por curiosidad, ¿alguna idea de cuándo habrá un lanzamiento (alfa / beta / lo que sea) de Guava? La página de inicio del proyecto es un poco corta en esto.
Jonik el
¡No hay pavo para mí hasta que salga!
Kevin Bourrillion el
El motivo es increíblemente extraño y no puedo explicarlo, pero está relacionado con la seguridad : puede crear una Cadena modificable a través de charsets personalizados, aunque podrían haberse hecho funcionar incluso más rápido que la cadena (que en realidad busca el conjunto de caracteres). Es una omisión / negligencia cómo String(byte bytes[], int offset, int length, Charset charset)se implementa. De hecho, el impacto en el rendimiento no es trivial cuando se crea una cadena pequeña a partir de un byte grande [].
bestsss
77
¡No es justo! Tienes acceso a tan buenos recursos. = (Vi otra respuesta donde una vez dijiste: "Sí, así que le pregunté a Josh [Bloch] sobre eso ..."
kevinarpe
PrintStream no es compatible con Charset
rofrol
102

Dos años después, y StandardCharsets de Java 7 ahora define constantes para los 6 charsets estándar.

Si está atascado en Java 5/6, puede usar las constantes Charsets de Guava , como lo sugieren Kevin Bourrillion y Jon Skeet.

Etienne Neveu
fuente
29

Yo diría que podemos hacerlo mucho mejor que eso ... ¿por qué no se puede acceder directamente a los charsets garantizados? Charset.UTF8debería ser una referencia al Charset, no el nombre como una cadena. De esa manera no tendríamos que manejar UnsupportedEncodingExceptiontodo el lugar.

Eso sí, también creo que .NET eligió una mejor estrategia al usar UTF-8 en todas partes. Luego se arruinó al nombrar la propiedad de codificación "predeterminado del sistema operativo" simplemente Encoding.Default, que no es el valor predeterminado dentro de .NET :(

Volviendo a despotricar sobre el soporte de juegos de caracteres de Java: ¿por qué no hay un constructor para FileWriter/ FileReaderque toma un Charset? Básicamente, esas son clases casi inútiles debido a esa restricción: casi siempre necesita un InputStreamReaderalrededor de FileInputStreamo el equivalente para la salida :(

Enfermera, enfermera, ¿dónde está mi medicina?

EDITAR: Se me ocurre que esto realmente no ha respondido la pregunta. La respuesta real es, presumiblemente, "nadie involucrado lo pensó" o "alguien involucrado pensó que era una mala idea". Sugeriría encarecidamente que las clases de utilidad internas que proporcionan los nombres o conjuntos de caracteres eviten la duplicación alrededor de la base de código ... O simplemente podría usar la que usamos en Google cuando se escribió por primera vez esta respuesta . (Tenga en cuenta que a partir de Java 7, solo usaría StandardCharsetsen su lugar).

Jon Skeet
fuente
2
+1. Pero como un método en lugar de un campo para permitir la carga diferida (está bien, probablemente querrá UTF-8, pero hay algunos otros charsets sobre y puede que desee instalaciones similares para ellos). Lamentablemente, esto no parece ser muy popular entre quienes toman las decisiones.
Tom Hawtin - tackline el
Estaría bastante contento con un método, aunque espero que cargar ansiosamente esos pocos charsets no sea un costo significativo.
Jon Skeet el
1
Estamos en una cruzada para detener la carga ansiosa de clases. / Acabo de buscar un JDK para "UTF-8". Encontradas 270 coincidencias en 165 archivo (s). Aunque mucho de eso está en la vieja basura de Apache (creo que contribuyó con mi equipo).
Tom Hawtin - tackline el
1
@tackline: supongo que la ansiosa carga de clases es una de esas cosas que aumenta con el tiempo. Unas pocas clases aquí, unas pocas clases allí, cada una individualmente sonando lo suficientemente inocuas, podrían hacer una gran diferencia.
Jon Skeet el
El último enlace, a Guava Charsets, está roto.
LarsH
28

En Java 1.7

import java.nio.charset.StandardCharsets

ex: StandardCharsets.UTF_8 StandardCharsets.US_ASCII

Roger
fuente
5

El estado actual de la API de codificación deja algo que desear. Algunas partes de la API de Java 6 no aceptan Charseten lugar de una cadena (en logging, dom.ls, PrintStream, puede haber otros). No ayuda que se supone que las codificaciones tienen diferentes nombres canónicos para diferentes partes de la biblioteca estándar.

Puedo entender cómo llegaron las cosas a donde están; No estoy seguro de tener alguna idea brillante sobre cómo solucionarlos.


Como un aparte...

Puede buscar los nombres de la implementación Java 6 de Sun aquí .

Para UTF-8, los valores canónicos son "UTF-8"para java.nioy "UTF8"para java.langy java.io. Las únicas codificaciones que la especificación requiere un JRE para admitir son: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16 .

McDowell
fuente
2
No me molesta el PrintStream, ya que la clase dice claramente "La clase PrintWriter debe usarse en situaciones que requieren escribir caracteres en lugar de bytes". (Que es, como, todas las situaciones ...)
Kevin Bourrillion
2

Hace mucho tiempo definí una clase de utilidad con las constantes UTF_8, ISO_8859_1 y US_ASCII Charset.

También, hace algún tiempo (2+ años) me hizo un simple análisis de rendimiento entre new String( byte[], Charset )y new String( byte[], String charset_name )y descubrió que esta última aplicación es CONSIDERABLEMENTE más rápido. Si observa el código fuente debajo del capó, verá que de hecho siguen un camino bastante diferente.

Por esa razón, incluí una utilidad en la misma clase

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

Por qué el constructor String (byte [], Charset) no hace lo mismo, me gana.

Alexander Pogrebnyak
fuente
1
La Charsetnecesidad no debe registrarse, por lo que la excepción puede suceder. IIRC, hubo algunos cambios en JDK7 para hacerlo más rápido para Charsetimplementaciones bien conocidas (eliminar la copia adicional).
Tom Hawtin - tackline