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个Java
char
,而编码为4个字节的代码点需要2个Java
char
一起工作。@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;
        }
    }