如何修剪java stringbuilder?

Cod*_*ile 14 java string optimization stringbuilder android

我有一个需要修剪的StringBuilder对象(即所有空格字符/ u0020及以下从任一端删除).

我似乎无法在字符串生成器中找到可以执行此操作的方法.

这就是我现在正在做的事情:

String trimmedStr = strBuilder.toString().trim();
Run Code Online (Sandbox Code Playgroud)

这给出了所需的输出,但它需要分配两个字符串而不是一个.在字符串仍在StringBuilder中时,是否更有效地修剪字符串?

Zav*_*yan 25

您不应该使用deleteCharAt方法.

正如Boris指出的那样,deleteCharAt方法每次都会复制数组.Java 5中执行此操作的代码如下所示:

public AbstractStringBuilder deleteCharAt(int index) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    System.arraycopy(value, index+1, value, index, count-index-1);
    count--;
    return this;
}
Run Code Online (Sandbox Code Playgroud)

当然,单凭推测还不足以选择一种优化方法而不是另一种方法,因此我决定在这个线程中计算3种方法:原始方法,删除方法和子字符串方法.

这是我为orignal测试的代码:

public static String trimOriginal(StringBuilder sb) {
    return sb.toString().trim();
}
Run Code Online (Sandbox Code Playgroud)

删除方法:

public static String trimDelete(StringBuilder sb) {
    while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) {
        sb.deleteCharAt(0);
    }
    while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) {
        sb.deleteCharAt(sb.length() - 1);
    }
    return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)

子串方法:

public static String trimSubstring(StringBuilder sb) {
    int first, last;

    for (first=0; first<sb.length(); first++)
        if (!Character.isWhitespace(sb.charAt(first)))
            break;

    for (last=sb.length(); last>first; last--)
        if (!Character.isWhitespace(sb.charAt(last-1)))
            break;

    return sb.substring(first, last);
}
Run Code Online (Sandbox Code Playgroud)

我执行了100次测试,每次都生成一个百万字符的StringBuffer,其中包含一万个尾随和前导空格.测试本身是非常基础的,但它可以很好地了解这些方法需要多长时间.

以下是对3种方法进行计时的代码:

public static void main(String[] args) {

    long originalTime = 0;
    long deleteTime = 0;
    long substringTime = 0;

    for (int i=0; i<100; i++) {

        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        StringBuilder sb3 = new StringBuilder();

        for (int j=0; j<10000; j++) {
            sb1.append(" ");
            sb2.append(" ");
            sb3.append(" ");
        }
        for (int j=0; j<980000; j++) {
            sb1.append("a");
            sb2.append("a");
            sb3.append("a");
        }
        for (int j=0; j<10000; j++) {
            sb1.append(" ");
            sb2.append(" ");
            sb3.append(" ");
        }

        long timer1 = System.currentTimeMillis();
        trimOriginal(sb1);
        originalTime += System.currentTimeMillis() - timer1;

        long timer2 = System.currentTimeMillis();
        trimDelete(sb2);
        deleteTime += System.currentTimeMillis() - timer2;

        long timer3 = System.currentTimeMillis();
        trimSubstring(sb3);
        substringTime += System.currentTimeMillis() - timer3;
    }

    System.out.println("original:  " + originalTime + " ms");
    System.out.println("delete:    " + deleteTime + " ms");
    System.out.println("substring: " + substringTime + " ms");
}
Run Code Online (Sandbox Code Playgroud)

我得到以下输出:

original:  176 ms
delete:    179242 ms
substring: 154 ms
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,子串方法提供了对原始"双字符串"方法的非常轻微的优化.但是,删除方法非常慢,应该避免.

所以回答你的问题:你可以按照你在问题中建议的方式修剪StringBuilder.子串方法提供的非常轻微的优化可能不能证明多余的代码.