快捷搜索:  汽车  科技

java字符串处理性能(提升Java字符串编码解码性能的技巧)

java字符串处理性能(提升Java字符串编码解码性能的技巧)static int writeUtf16LE(char[] chars int off int len byte[] dest final int dp) { UNSAFE.copyMemory(chars CHAR_ARRAY_BASE_OFFSET off * 2 dest BYTE_ARRAY_BASE_OFFSET dp len * 2 ); dp = len * 2; return dp; }3 Java String的编码不同版本的JDK String的实现不一样,从而导致有不同的性能表现。char是UTF-16编码,但String在JDK 9之后内部可以有LATIN1编码。如下是一个将UTF-16转换为UTF-8编

简介:常见的字符串编码有LATIN1、UTF-8、UTF-16、GB18030,他们各有各的特点,且之间的转换比较复杂。本文将为大家介绍提升Java字符串编码解码性能的技巧。

java字符串处理性能(提升Java字符串编码解码性能的技巧)(1)

作者 | 温绍锦 (高铁)
来源 | 阿里开发者公众号

1 常见字符串编码

常见的字符串编码有:

  • LATIN1 只能保存ASCII字符,又称ISO-8859-1。
  • UTF-8 变长字节编码,一个字符需要使用1个、2个或者3个BYTE表示。由于中文通常需要3个字节表示,中文场景UTF-8编码通常需要更多的空间,替代的方案是GBK/GB2312/GB18030。
  • UTF-16 2个字节,一个字符需要使用2个byte表示,又称UCS-2 (2-byte Universal character Set)。根据大小端的区分,UTF-16有两种形式,UTF-16BE和UTF-16LE,缺省UTF-16指UTF-16BE。Java语言中的char是UTF-16LE编码。
  • GB18030 变长字节编码,一个字符需要使用1个、2个或者3个byte表示。类似UTF8,中文只需要2个字符,表示中文更省字节大小,缺点是在国际上不通用。

java字符串处理性能(提升Java字符串编码解码性能的技巧)(2)

为了计算方便,内存中字符串通常使用等宽字符,Java语言中char和.NET中的char都是使用UTF-16。早期Windows-NT只支持UTF-16。

2 编码转换性能

UTF-16和UTF-8之间转换比较复杂,通常性能较差。

java字符串处理性能(提升Java字符串编码解码性能的技巧)(3)

如下是一个将UTF-16转换为UTF-8编码的实现,可以看出算法比较复杂,所以性能较差,这个操作也无法使用vector API做优化。

static int encodeUTF8(char[] utf16 int off int len byte[] dest int dp) { int sl = off len last_offset = sl - 1; while (off < sl) { char c = utf16[off ]; if (c < 0x80) { // Have at most seven bits dest[dp ] = (byte) c; } else if (c < 0x800) { // 2 dest 11 bits dest[dp ] = (byte) (0xc0 | (c >> 6)); dest[dp ] = (byte) (0x80 | (c & 0x3f)); } else if (c >= '\uD800' && c < '\uE000') { int uc; if (c < '\uDC00') { if (off > last_offset) { dest[dp ] = (byte) '?'; return dp; } char d = utf16[off]; if (d >= '\uDC00' && d < '\uE000') { uc = (c << 10) d 0xfca02400; } else { throw new RuntimeException("encodeUTF8 error" new MalformedInputException(1)); } } else { uc = c; } dest[dp ] = (byte) (0xf0 | ((uc >> 18))); dest[dp ] = (byte) (0x80 | ((uc >> 12) & 0x3f)); dest[dp ] = (byte) (0x80 | ((uc >> 6) & 0x3f)); dest[dp ] = (byte) (0x80 | (uc & 0x3f)); off ; // 2 utf16 } else { // 3 dest 16 bits dest[dp ] = (byte) (0xe0 | ((c >> 12))); dest[dp ] = (byte) (0x80 | ((c >> 6) & 0x3f)); dest[dp ] = (byte) (0x80 | (c & 0x3f)); } } return dp; }

相关代码地址[1] 。

由于Java中char是UTF-16LE编码,如果需要将char[]转换为UTF-16LE编码的byte[]时,可以使用sun.misc.Unsafe#copyMemory方法快速拷贝。比如:

static int writeUtf16LE(char[] chars int off int len byte[] dest final int dp) { UNSAFE.copyMemory(chars CHAR_ARRAY_BASE_OFFSET off * 2 dest BYTE_ARRAY_BASE_OFFSET dp len * 2 ); dp = len * 2; return dp; }

3 Java String的编码

不同版本的JDK String的实现不一样,从而导致有不同的性能表现。char是UTF-16编码,但String在JDK 9之后内部可以有LATIN1编码。


点击链接查看原文,关注公众号【阿里开发者】获取更多福利!https://mp.weixin.qq.com/s/dhZhAV4cXC0kEYprunAUXg
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

猜您喜欢: