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字符串编码解码性能的技巧。作者 | 温绍锦 (高铁)
来源 | 阿里开发者公众号
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语言中char和.NET中的char都是使用UTF-16。早期Windows-NT只支持UTF-16。
2 编码转换性能
UTF-16和UTF-8之间转换比较复杂,通常性能较差。
如下是一个将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编码。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。