当你必须遍历一个集合并用分隔符将每个数据组成一个字符串时,你总是会在最后得到一个额外的分隔符,例如:

for (String serverId : serverIds) {
  sb.append(serverId);
   sb.append(",");
}

给出类似serverId_1 serverId_2 serverId_3

我想删除StringBuilder中的最后一个字符(不转换它,因为在这个循环之后我仍然需要它)。


当前回答

另一个简单的解决方案是:

sb.setLength(sb.length() - 1);

一个更复杂的解决方案:

上述解决方案假设sb.length() > 0…也就是说,有一个“最后一个字符”要删除。如果你不能做这样的假设,和/或你不能处理异常,将随之而来的假设是不正确的,然后先检查StringBuilder的长度;如。

// Readable version
if (sb.length() > 0) {
   sb.setLength(sb.length() - 1);
}

or

// Concise but harder-to-read version of the above.
sb.setLength(Math.max(sb.length() - 1, 0));

其他回答

另一种替代方法

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
sb.deleteCharAt(0);

在这种情况下,

sb.setLength(sb.length() - 1);

是可取的,因为它只是将最后一个值分配给'\0',而删除最后一个字符的System.arraycopy

我发现自己经常这样做,所以我为3种主要的附加分隔符技术写了一个基准测试: (具有适当预热和100轮100,000次迭代的基准测试)

“附加”

static void appendAfter()
{
    sb.append('{');
    for (int i = 0; i < 10; i++)
    {
        sb.append('"');
        sb.append(i);
        sb.append('"');
        sb.append(':');
        sb.append(i);
        sb.append(',');
    }
    sb.setLength(sb.length() - 1);
    sb.append('}');
}

“添加”

static void appendBefore()
{
    sb.append('{');
    String delimiter = "";
    for (int i = 0; i < 10; i++)
    {
        sb.append(delimiter);
        sb.append('"');
        sb.append(i);
        sb.append('"');
        sb.append(':');
        sb.append(i);
        delimiter = ",";
    }
    sb.append('}');
}

“附加也许”

static void appendMaybe()
{
    sb.append('{');
    for (int i = 0; i < 10; i++)
    {
        sb.append('"');
        sb.append(i);
        sb.append('"');
        sb.append(':');
        sb.append(i);
        if (i < 9)
        {
            sb.append(',');
        }
    }
    sb.append('}');
}

我得到了以下结果:

Platform Append After Append Before Append Maybe
Windows Server 2016, Java 11 - Hotspot 26ms 40ms 26ms
Windows Server 2016, Java 8 - Hotspot 27ms 36ms 21ms
Windows Server 2016, Java 11 - OpenJ9 63ms 81ms 59ms
Windows Server 2016, Java 8 - OpenJ9 66ms 64ms 55ms

除了最快之外,我认为“Append Maybe”实现最好地展示了代码的意图。这通常比每次迭代获得的纳秒分数更重要。

我把基准代码留在这里,以防有人想在自己的平台上尝试它。如果你这样做,请贡献你的结果!

还有另一种选择:

public String join(Collection<String> collection, String seperator) {
    if (collection.isEmpty()) return "";

    Iterator<String> iter = collection.iterator();
    StringBuilder sb = new StringBuilder(iter.next());
    while (iter.hasNext()) {
        sb.append(seperator);
        sb.append(iter.next());
    }

    return sb.toString();
}

另外,

StringBuilder result = new StringBuilder();
for(String string : collection) {
    result.append(string);
    result.append(',');
}
return result.substring(0, result.length() - 1) ;