2009-11-05 9 views
199

Los problemas del conjunto de caracteres son confusos y complicados por sí mismos, pero además de eso, debe recordar los nombres exactos de sus conjuntos de caracteres. ¿Es "utf8"? O "utf-8"? O tal vez "UTF-8"? Al buscar muestras de código en Internet, verá todo lo anterior. ¿Por qué no simplemente hacerlos constantes con nombre y usar Charset.UTF8?Java: ¿Por qué los nombres de los conjuntos de caracteres no son constantes?

+18

+1: Esto también me estaba molestando todo el tiempo. La misma historia continúa para 'MessageDigest # getInstance()' por cierto. – BalusC

+1

Para la respuesta real, necesitarías preguntarle a alguien en Sun. Buena suerte con eso :-) –

+1

Stephen C: Creo que ha sido discutido en una lista de correo pública. Alguien en Sun. –

Respuesta

152

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

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

JDK 1.4 hizo algo genial al introducir el tipo de Charset. En este punto, ya no habrían querido proporcionar constantes String, ya que el objetivo es lograr que todos usen instancias Charset. Entonces, ¿por qué no proporcionar las seis constantes estándar de Charset? Le pregunté a Martin Buchholz, ya que él estaba sentado a mi lado, y me dijo que no había una razón particularmente importante, excepto que en ese momento, las cosas aún estaban medio cocidas: muy pocas API de JDK habían sido adaptadas para acepta Charset, y de los que sí lo fueron, las sobrecargas de Charset solían tener un peor rendimiento.

Es triste que solo en el JDK 1.6 hayan acabado 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 raro y no puedo explicarlo, ¡pero está relacionado con la seguridad!).

Relativamente corto: simplemente defina sus propias constantes, o utilice la clase de Conjuntos de Guava a la que Tony el Pony se vinculó (aunque esa biblioteca realmente no se haya lanzado todavía).

Actualización: una clase StandardCharsets está en JDK 7.

+0

Simplemente curioso, ¿alguna idea de cuándo habrá un lanzamiento (alfa/beta/lo que sea) de guayaba? La página de inicio del proyecto es un poco cortante en esto. – Jonik

+0

¡No hay pavo para mí hasta que salga! –

+0

* la razón por la que es increíblemente raro y no puedo explicarlo, pero está relacionado con la seguridad *: puede crear una cadena modificable a través de conjuntos de caracteres personalizados, sin embargo, podrían haberse realizado incluso más rápido que la cadena (que realmente busca el juego de caracteres). Es una omisión/negligencia cómo se implementa 'String (byte bytes [], int offset, int length, Charset charset)'. De hecho, el golpe de rendimiento no es para nada trivial cuando se crea una pequeña cadena de un byte grande []. – bestsss

27

Argumentaría que podemos hacer mucho mejor que eso ... ¿por qué no se puede acceder directamente a los conjuntos de caracteres garantizados? Charset.UTF8 debe ser una referencia al Charset, no el nombre como una cadena. De esa forma no tendríamos que manejar UnsupportedEncodingException por todo el lugar.

Tenga en cuenta que también creo que .NET eligió una mejor estrategia por defecto a UTF-8 en todas partes. Se enrosca entonces por nombrar el "defecto del sistema operativo" codificación de la propiedad simplemente Encoding.Default - lo cual no es al impago en .NET sí :(

Volver a despotricar sobre el apoyo conjunto de caracteres de Java - por qué no hay un constructor ? para FileWriter/FileReader que toma un Charset Básicamente esas son las clases casi inútil debido a que la restricción - casi siempre se necesita un InputStreamReader alrededor de un FileInputStream o el equivalente para la salida :(

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

EDITAR: Se me ocurre que esto no ha respondido realmente a la pregunta. La respuesta real es presumiblemente "nadie pensó en ello" o "alguien involucrado pensó que era una mala idea". Sugiero encarecidamente que las clases de utilidad interna que proporcionan los nombres o conjuntos de caracteres eviten la duplicación en la base del código ... O simplemente podría usar the one that we use at Google.

+2

+1. Pero como un método en lugar de un campo para permitir la carga diferida (está bien, es probable que desee UTF-8, pero hay algunos otros conjuntos de caracteres y es posible que desee instalaciones similares para ellos). Desafortunadamente, esto no parece ser muy popular entre los que toman las decisiones. –

+0

Estaría contento con un método, aunque espero que cargar ansiosamente esos pocos conjuntos no suponga un gasto significativo. –

+1

Estamos en una cruzada para detener la ardua carga de clases./Acabo de buscar un JDK para "UTF-8". Encontrados 270 resultado (s) en 165 archivo (s).Aunque mucho de eso está en la basura vieja de Apache (creo que contribuido por mi equipo). –

5

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

Entiendo cómo llegaron las cosas a su ubicación; no estoy seguro de tener ideas brillantes sobre cómo solucionarlos.


Como acotación al margen ...

Puede buscar los nombres de ejecución Java 6 here del solar.

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

+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 ...) –

2

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

Además, hace algún tiempo (2+ años) me hizo una prueba de rendimiento simple 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 echas un vistazo debajo del capó en el código fuente, verás que de hecho siguen un camino bastante diferente.

Por esa razón por la que incluyó una utilidad de 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é la cadena (byte [], juego de caracteres) constructor no haga lo mismo, me pega.

+1

El 'Charset' no necesita ser registrado, por lo que la excepción puede ocurrir. IIRC, hubo algunos cambios en JDK7 para hacerlo más rápido para las implementaciones conocidas de' Charset' (eliminar la copia extra). –

99

Dos años más tarde, y en Java 7 StandardCharsets ahora se definen constantes para los 6 conjuntos de caracteres estándar.

Si está atascado en Java 5/6, puede usar las constantes de Charsets de Guava, según lo sugerido por Kevin Bourrillion y Jon Skeet.

26

En Java 1,7

import java.nio.charset.StandardCharsets

ejemplo: StandardCharsets.UTF_8 StandardCharsets.US_ASCII

Cuestiones relacionadas