删除 StringBuilder 的最后一个字符?

问题描述 投票:0回答:19

当您必须循环遍历集合并使用分隔符分隔每个数据的字符串时,您总是会在末尾有一个额外的分隔符,例如

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

提供类似以下内容:serverId_1、serverId_2、serverId_3、

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

java stringbuilder
19个回答
741
投票

其他人指出了

deleteCharAt
方法,但这里有另一种替代方法:

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

或者,使用 Guava

 中的 
Joiner 类 :)

从 Java 8 开始,

StringJoiner
是标准 JRE 的一部分。


546
投票

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

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

更复杂的解决方案:

上述解决方案假设

sb.length() > 0
...即有一个“最后一个字符”需要删除。如果您无法做出该假设,和/或您无法处理假设不正确时会出现的异常,那么首先检查 StringBuilder 的长度;例如

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

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

222
投票
if(sb.length() > 0){
    sb.deleteCharAt(sb.length() - 1);
}

68
投票

从 Java 8 开始,String 类有一个静态方法

join
。第一个参数是每对字符串之间所需的字符串,第二个参数是
Iterable<CharSequence>
(它们都是接口,因此类似
List<String>
的东西可以工作。所以你可以这样做:

String.join(",", serverIds);

同样在 Java 8 中,您可以使用新的

StringJoiner
类,适用于您想要在放入完整元素列表之前开始构造字符串的情况。


49
投票

只需获取最后一个字符出现的位置即可。

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

由于

lastIndexOf
将执行反向搜索,并且您知道它会在第一次尝试时找到,因此性能在这里不会成为问题。

编辑

由于我的回答一直在提高(谢谢大家😊),因此值得考虑:

Java 8 之后,使用 StringJoiner 会更加清晰和明确。 它有一种简单分隔符的方法,以及前缀和后缀的重载。

示例取自此处:example

使用简单分隔符的示例:

    StringJoiner mystring = new StringJoiner("-");    

    // Joining multiple strings by using add() method  
    mystring.add("Logan");  
    mystring.add("Magneto");  
    mystring.add("Rogue");  
    mystring.add("Storm");  

    System.out.println(mystring);

输出:

洛根-万磁王-盗贼-风暴

带有后缀和前缀的示例:

    StringJoiner mystring = new StringJoiner(",", "(", ")");    

    // Joining multiple strings by using add() method  
    mystring.add("Negan");  
    mystring.add("Rick");  
    mystring.add("Maggie");  
    mystring.add("Daryl");  

    System.out.println(mystring);

输出

(尼根、瑞克、玛吉、达里尔)


40
投票

在这种情况下,

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

更好,因为它只是将最后一个值分配给

'\0'
,而删除最后一个字符则
System.arraycopy


12
投票

通过

Java-8
,您可以使用
String
类的静态方法,

String#join(CharSequence delimiter,Iterable<? extends CharSequence> elements)


public class Test {

    public static void main(String[] args) {

        List<String> names = new ArrayList<>();
        names.add("James");
        names.add("Harry");
        names.add("Roy");
        System.out.println(String.join(",", names));
    }
}

输出

James,Harry,Roy

10
投票

另一种选择

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

9
投票

或者,

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

6
投票
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true

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);
            }

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
投票

我正在做如下的事情:

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

1
投票

我发现自己经常这样做,所以我为 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('}');
}

我得到了以下结果:

平台 添加到之后 添加到之前 也许追加
Windows Server 2016、Java 11 - 热点 26毫秒 40毫秒 26毫秒
Windows Server 2016、Java 8 - 热点 27毫秒 36毫秒 21毫秒
Windows Server 2016、Java 11 - OpenJ9 63毫秒 81ms 59ms
Windows Server 2016、Java 8 - OpenJ9 66毫秒 64毫秒 55毫秒

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

我留下了基准代码here,以防有人想在他们的平台上尝试。如果您这样做,请在上面贡献您的结果!


0
投票

这是另一种解决方案:

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

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

0
投票

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


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);
}
© www.soinside.com 2019 - 2024. All rights reserved.