Java—检查字符串大小的最快方法
循环语句中包含以下代码。Java—检查字符串大小的最快方法,java,utf-8,java-8,Java,Utf 8,Java 8,循环语句中包含以下代码。 在循环中,字符串被附加到sb(StringBuilder)并检查sb的大小是否已达到5MB if (sb.toString().getBytes("UTF-8").length >= 5242880) { // Do something } 这很好,但速度非常慢(在检查大小方面) 最快的方法是什么 如果循环1000次,将生成1000String,然后转换为“UTF-8字节”数组,以获得长度 我将通过存储第一个长度来减少转换。然后,在每个循环上,只获取附加
在循环中,字符串被附加到sb(StringBuilder)并检查sb的大小是否已达到5MB
if (sb.toString().getBytes("UTF-8").length >= 5242880) {
// Do something
}
这很好,但速度非常慢(在检查大小方面)最快的方法是什么 如果循环1000次,将生成1000String,然后转换为“UTF-8字节”数组,以获得长度 我将通过存储第一个长度来减少转换。然后,在每个循环上,只获取附加值的长度,然后这只是一个加法
int length = sb.toString().getBytes("UTF-8").length;
for(String s : list){
sb.append(s);
length += s.getBytes("UTF-8").length;
if(...){
...
}
}
这将减少使用的内存和转换成本您可以使用
public static int utf8Length(CharSequence cs) {
return cs.codePoints()
.map(cp -> cp<=0x7ff? cp<=0x7f? 1: 2: cp<=0xffff? 3: 4)
.sum();
}
这假设如果您要附加包含代理项对的片段,那么它们总是完整的,并且不会拆分为两半。对于普通应用,应始终如此
建议的另一种可能性是推迟计算,直到您的
StringBuilder
达到阈值长度除以三,与之前一样,UTF-8
长度不可能大于阈值。但是,只有在某些执行中没有达到阈值/3
时,这才是有益的。考虑使用ByteArrayOutputStream和OutputStreamWriter而不是StringBuilder。使用ByteArrayOutputStream.size()测试大小。作为进一步优化,请注意字符最多占用3个字节,您还可以避免计算长度,直到StringBuilder
长度达到5MB/3。@Holger在jdk-9中,将有String::codePoints
来区分ASCII字符串和非ASCII字符串。。。此外,该技术仅适用于UTF-8,它仍然很好。@尤金:计算UTF-8
长度是本练习的唯一目的。除此之外,Java 9对codePoints()
的实现不会对这个答案产生影响。此答案的两个解决方案之间的区别在于,第二个解决方案仅对ASCII字符执行一个条件,并跳过加法操作。修正错误后,这两种变体在最坏的情况下不再有差异,因此第二种变体始终获胜。一个便宜的“isAllASCII”方法会有帮助,但据我所知,Java 9只会在内部区分iso-latin-1和其他字符串。@Didierr:“一个字符最多需要3个字节”-一个char
,是的,但Java字符串代表UTF-16中的Unicode码点,因此,字符串中的每个码点可能有1或2个char
s。在标准UTF-8中,代码点最多可编码4个字节,其中编码最多3个字节的代码点只需要1个Javachar
,而编码为4个字节的代码点需要2个Javachar
一起工作。@RemyLebeau这不会改变我的推理,因为length()字符串的
/StringBuilder
是char
s的数量,因此如果一个码点取2个char
s,它最多会计为6个字节,这仍然被高估,因此与此优化兼容。
public static int utf8Length(CharSequence cs) {
return cs.length()
+ cs.codePoints().filter(cp -> cp>0x7f).map(cp -> cp<=0x7ff? 1: 2).sum();
}
StringBuilder sb = new StringBuilder();
int length = 0;
for(…; …; …) {
String s = … //calculateNextString();
sb.append(s);
length += utf8Length(s);
if(length >= 5242880) {
// Do something
// in case you're flushing the data:
sb.setLength(0);
length = 0;
}
}