如何从 StringBuilder 中删除最后一个字符?

528
当你需要遍历一个集合并将每个数据用分隔符分开组成一个字符串时,最后总会多余一个分隔符,例如:
for (String serverId : serverIds) {
  sb.append(serverId);
   sb.append(",");
}

结果类似于: serverId_1, serverId_2, serverId_3,

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


11
如果加入字符串意味着“字符串拼接”,那么它取决于字符串的数量和长度。如果您将要连接大量字符串,而且这些字符串的大小不确定,使用字符串生成器会更有效率,因为字符串是不可变的。每次连接字符串时,都会创建一个新的结果字符串(实际上是一个字符数组)。字符串生成器本质上是一个字符列表,在调用toString()方法之前不会成为不可变的字符串。 - dyslexicanaboko
7
如果您在使用Java 8,则只需使用StringJoiner:https://dev59.com/enA75IYBdhLWcg3wP2kg#29169233 - ArtOfWarfare
19个回答

5
另一个选择:
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();
}

3
为了避免重新初始化(影响性能)prefix,请使用TextUtils.isEmpty:
            String prefix = "";
            for (String item : list) {
                sb.append(prefix);
                if (TextUtils.isEmpty(prefix))
                    prefix = ",";
                sb.append(item);
            }

TestUtils属于哪种包? - Markus
@Markus android.text.TextUtils@Markus android.text.TextUtils - NickUnuchek

1
我正在做如下的事情:

    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < value.length; i++) {
        stringBuilder.append(values[i]);
        if (value.length-1) {
            stringBuilder.append(", ");
        }
    }

1
你可以尝试使用“Joiner”类来代替从生成的文本中删除最后一个字符;
                List<String> textList = new ArrayList<>();
                textList.add("text1");
                textList.add("text2");
                textList.add("text3");

                Joiner joiner = Joiner.on(",").useForNull("null");
                String output = joiner.join(textList);

               //output : "text1,text2,text3"

1
我发现自己经常这样做,所以我为三种主要的追加分隔符技术编写了一个基准测试: (进行适当的预热和100轮10万次迭代的基准测试) “追加后”
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('}');
}

"Append Before"(在之前添加)
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('}');
}

我得到了以下结果:
平台 后附加 前附加 可能附加
Windows Server 2016,Java 11 - Hotspot 26毫秒 40毫秒 26毫秒
Windows Server 2016,Java 8 - Hotspot 27毫秒 36毫秒 21毫秒
Windows Server 2016,Java 11 - OpenJ9 63毫秒 81毫秒 59毫秒
Windows Server 2016,Java 8 - OpenJ9 66毫秒 64毫秒 55毫秒
除了速度最快之外,我认为“可能附加”实现最能表现代码的意图,这通常比每次迭代获得的纳秒分数更重要。

我在这里留下了基准测试代码here,以便任何人都可以在其平台上尝试。如果您这样做,请在上面贡献您的结果!


你试过删除最后一个字符吗?对我来说,这样似乎更高效,因为可以在for循环之外完成删除最后一个字符的操作。 - canbax

0

stringBuilder.Remove(stringBuilder.Length - 1, 1);

字符串生成器。删除(字符串生成器.长度 - 1,1);


没有remove方法。而Length(或length)不是字段,它是一个方法。 - Stephen C
我认为这可能是C#。 - TheKodeToad

0

这里有另一个解决方案:

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

String resultingString = "";
if ( sb.length() > 1 ) {
    resultingString = sb.substring(1);
}

但无论如何,这只是Zaki在2010年解决方案的一个小变体。 - Stephen C

0
如果你不想使用StringJoiner,这里有一个对@superpupervlad技术的小改进(对于大型列表有很大的收益),可以减少赋值的次数。
char prefix = '\0'; // same as ""
for (String serverId : serverIds) {
  sb.append(prefix);
  if (prefix == '\0') prefix = ',';
  sb.append(serverId);
}

0
一个更简单和紧凑的解决方案只需要对您的代码进行小的修改。
for (String serverId : serverIds) {
  if (!sb.isEmpty()) sb.append(",")
  sb.append(serverId);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接