来自 UTF-8 的字符串构造函数是否损坏?

Is the String Constructor from UTF-8 Broken?

我有以下代码从缓冲区加载空终止的多字节字符串。它名义上将数据解释为 UTF-8,但如果转换失败,它会将数据解释为 ISO-8859-1。这是代码:

@Override
   public String format(String date_format, boolean use_locale, int precision)
   {
      String rtn = null;
      int len = 0;
      for(int i = 0; i < max_len; ++i)
      {
         if(storage[storage_offset + i] != 0)
            ++len;
         else
            break;
      }
      try
      {
         rtn = new String(storage, storage_offset, len, "UTF-8");
      }
      catch(UnsupportedEncodingException e1)
      {
         try
         {
            rtn = new String(storage, storage_offset, len, "ISO-8859-1");
         }
         catch(UnsupportedEncodingException e2)
         { }
      }
      return rtn;
   }

我的意图是,如果 UTF-8 的字符串解码失败,我们可以回退。这取决于抛出的 UnsupportedEncodingException。我对这段代码进行了 运行 测试,该代码通过了扩展字符(大于 128 的代码),但没有预期的 UTF-8 模式。我发现没有抛出异常,并且正在为转换后的字符串显示未知字形。我的问题是标准库实现是否有任何更改会导致不抛出异常?

如果字符集本身不受支持(即,您指定了一个字符集,但系统无法识别该名称),则会抛出 UnsupportedEncodingException——如果字节编码不正确,则不会。请注意,采用 java.nio.charset.Charset 的相应构造函数确实 而不是 抛出该异常(因为没有名称映射到 Charset,因此映射不可能不存在)。

String(byte[], int, int, String) 的文档指定了行为(即未指定 :))并提出了修复建议:

The behavior of this constructor when the given bytes are not valid in the given charset is unspecified. The CharsetDecoder class should be used when more control over the decoding process is required.

根据 that String constructor 的文档,仅当指定的 charsetName 未知时才会抛出 UnsupportedEncodingException。

The behavior of this constructor when the given bytes are not valid in the given charset is unspecified. The CharsetDecoder class should be used when more control over the decoding process is required.

您可以测试字符集是否可用。
要获得可用的字符集,请使用:

SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
    for (Map.Entry<String, Charset> entrySet : availableCharsets.entrySet()) {
        String key = entrySet.getKey();
        Charset value = entrySet.getValue();
        System.out.println("key: " + key + " value: " + value.name());
    }
    System.out.println("The default Charset is: " + Charset.defaultCharset().name());