为什么字符集名称不是常量?


211

字符集问题本身令人困惑和复杂,但是最重要的是,您必须记住字符集的确切名称。是"utf8"吗 还是"utf-8"?也许"UTF-8"呢?在Internet上搜索代码示例时,将看到上述所有内容。为什么不让它们命名为常数并使用Charset.UTF8呢?


19
+1:这也一直困扰着我。MessageDigest#getInstance()顺便说说同样的故事。
BalusC,2009年

2
要获得真正的答案,您需要在Sun咨询某人。祝你好运:-)
Stephen C

1
Stephen C:我相信已经在公共邮件列表中进行了讨论。-有人在太阳。
汤姆·哈特芬

Answers:


160

对所提问题的简单回答是,可用的字符集字符串因平台而异。

但是,必须存在六个,因此对于那些很早以前就可以建立常数。我不知道为什么他们没有。

JDK 1.4通过引入Charset类型做了一件了不起的事情。在这一点上,他们不再想要提供String常量,因为目标是让所有人都使用Charset实例。那么,为什么不提供六个标准的Charset常数呢?我问马丁·布赫霍尔茨(Martin Buchholz),因为他刚好就坐在我旁边,他说并没有什么特别重要的理由,除了那个时候事情还不成熟–很少有JDK API可以改装接受Charset,在其中的一个中,Charset重载通常执行得稍差一些。

令人遗憾的是,直到最后在JDK 1.6中,他们才最终为所有组件配备了Charset重载。而且这种落后的性能状况仍然存在(之所以令人难以置信的怪异,我无法解释,而是与安全性相关!)。

长话短说-只需定义您自己的常量,或使用Guad的Charsets类(与Tony the Pony关联)即可(尽管该库尚未真正发布)。

更新:StandardCharsets JDK 7中有一个类。


只是好奇,什么时候会发布番石榴(alpha / beta /其他)?项目主页对此有些偏颇。
Jonik)

直到火鸡出来对我来说都没有火鸡!
凯文·布兰里恩

之所以令人难以置信的怪异,我无法解释,但与安全性有关,您可以通过自定义字符集创建可修改的String,但它们的工作原理甚至比string(实际上可以查询字符集)还快。这是一个遗漏/忽略String(byte bytes[], int offset, int length, Charset charset)的实现方式。实际上,从大字节[]创建小字符串时,性能的提高一点也不微不足道。
bestsss

7
不公平!您可以访问如此丰富的资源。=((我看到另一个答案,您曾经说过:“是的,所以我问了乔什·布洛赫(Josh [Bloch])这
件事

PrintStream不支持Charset
rofrol 2014年


29

我认为我们可以做得更好……为什么不能直接访问保证可用的字符集?Charset.UTF8应该是对的引用Charset,而不是作为字符串的名称。这样,我们就不必在UnsupportedEncodingException所有地方处理。

提醒您,我还认为.NET通过在各处默认使用UTF-8来选择更好的策略。然后,通过简单地命名“操作系统默认”编码属性来搞砸Encoding.Default-这不是 .NET本身的默认属性:(

回到对Java的字符集支持的狂热-为什么不为FileWriter/ 构造FileReader一个需要一个Charset?的构造函数?基本上,由于这种限制,那些几乎是无用的类-您几乎总是需要InputStreamReadera FileInputStream或等效的输出:(

护士,护士-我的药在哪里?

编辑:我想到这还没有真正回答问题。真正的答案大概是“没有人想到它”或“有人认为这是个坏主意”。我强烈建议提供名称或字符集的内部实用程序类避免在代码库中重复...否则,您可以使用在首次编写此答案时在Google上使用的那种实用程序。(请注意,从Java 7开始,您只需使用它即可StandardCharsets。)


2
+1。但是,作为一种允许延迟加载的方法而不是字段(好的,您可能会想要UTF-8,但是还有其他一些字符集,并且您可能想要类似的功能)。不幸的是,这似乎在做出决定的人中并不流行。
汤姆·霍顿

我对一种方法很满意,尽管我希望热切地加载那些很少的字符集不会有太大的花费。
乔恩·斯基特

1
我们正竭尽全力停止渴望上课的人。/只是在JDK中搜索了“ UTF-8”。在165个文件中找到270个匹配项。尽管其中很多是旧的Apache垃圾(我相信是由我的团队贡献的)。
Tom Hawtin-抢险

1
@tackline:我想渴望的类加载是随着时间的推移而增加的事情之一。这里有几节课,那里有几节课-每堂课听起来都很无害-可能会带来很大的不同。
乔恩·斯基特

到番石榴字符集的最后一个链接已断开。
LarsH

28

在Java 1.7中

import java.nio.charset.StandardCharsets

例如: StandardCharsets.UTF_8 StandardCharsets.US_ASCII


5

编码API的当前状态有待改进。Java 6的API的某些部分不接受Charset代替字符串(在loggingdom.lsPrintStream,有可能是其他人)。对于标准库的不同部分,编码应该具有不同的规范名称无济于事。

我能理解事物是如何到达的。不确定我对如何解决它们有任何出色的想法。


作为旁白...

您可以在此处查找Sun的Java 6实现的名称。

对于UTF-8,规范值为"UTF-8"for java.nio"UTF8"for java.langjava.io。规范要求JRE支持的唯一编码是:US-ASCII;ISO-8859-1;UTF-8;UTF-16BE; UTF-16LE; UTF-16


2
我不会讨厌PrintStream,因为该类确实明确地说:“在需要写入字符而不是字节的情况下,应使用PrintWriter类。” (这是所有情况下的情况...)
凯文·布瑞里恩

2

我很久以前用UTF_8,ISO_8859_1和US_ASCII Charset常量定义了一个实用程序类。

此外,一些很久以前(2年以上),我做之间的简单性能测试new String( byte[], Charset )new String( byte[], String charset_name ),发现后者的实现是相当快。如果您仔细查看源代码,您会发现它们确实遵循完全不同的路径。

因此,我在同一个类中包含了一个实用程序

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

为什么String(byte [],Charset)构造函数不做同样的事情,让我感到震惊。


1
Charset无须注册,所以异常可能发生。IIRC,JDK7中进行了一些更改,以使其更快地用于已知良好的Charset实现(消除多余的副本)。
汤姆·霍顿
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.