我在循环语句中有以下代码.
在循环中,字符串被附加到sb(StringBuilder)并检查sb的大小是否已达到5MB.
if (sb.toString().getBytes("UTF-8").length >= 5242880) {
// Do something
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,但它很慢(在检查大小方面)
最快的方法是什么?
Hol*_*ger 11
您可以UTF-8使用快速计算长度
public static int utf8Length(CharSequence cs) {
return cs.codePoints()
.map(cp -> cp<=0x7ff? cp<=0x7f? 1: 2: cp<=0xffff? 3: 4)
.sum();
}
Run Code Online (Sandbox Code Playgroud)
如果ASCII字符在内容中占主导地位,则使用起来可能会稍快一些
public static int utf8Length(CharSequence cs) {
return cs.length()
+ cs.codePoints().filter(cp -> cp>0x7f).map(cp -> cp<=0x7ff? 1: 2).sum();
}
Run Code Online (Sandbox Code Playgroud)
代替.
但是您也可以考虑不重新计算整个大小的优化潜力,而只考虑您要附加到的新片段的大小StringBuilder,类似的东西
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这假设如果你附加包含代理对的片段,它们总是完整的并且不会被分成两半.对于普通应用,情况应始终如此.
Didier-L建议的另一种可能性是推迟计算,直到StringBuilder达到阈值的长度除以3,如前所述,不可能有一个UTF-8大于阈值的长度.但是,如果碰巧threshold / 3在某些执行中没有达到,那么这将是有益的.
如果循环1000次,则会生成1000String,然后转换为"UTF-8 Byte"数组,以获得长度.
我会通过存储第一个长度来减少转换.然后,在每个循环上,只获取添加值的长度,然后这只是一个补充.
int length = sb.toString().getBytes("UTF-8").length;
for(String s : list){
sb.append(s);
length += s.getBytes("UTF-8").length;
if(...){
...
}
}
Run Code Online (Sandbox Code Playgroud)
这将减少使用的内存和转换成本