删除 StringBuilder 的最后一个字符?

发布于 2024-09-12 10:20:42 字数 282 浏览 7 评论 0原文

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

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

给出类似:serverId_1, serverId_2, serverId_3,

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

When you have to loop through a collection and make a string of each data separated by a delimiter, you always end up with an extra delimiter at the end, e.g.

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

Gives something like : serverId_1, serverId_2, serverId_3,

I would like to delete the last character in the StringBuilder (without converting it because I still need it after this loop).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

迷爱 2024-09-19 10:20:43

在这种情况下,

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

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

In this case,

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

is preferable as it just assign the last value to '\0' whereas deleting last character does System.arraycopy

简单爱 2024-09-19 10:20:43

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

String#join(CharSequence delimiter,Iterable 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

With Java-8 you can use static method of String class,

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

OUTPUT

James,Harry,Roy
べ繥欢鉨o。 2024-09-19 10:20:43

另一种选择

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

Another alternative

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
sb.deleteCharAt(0);
紫罗兰の梦幻 2024-09-19 10:20:43

或者,

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

Alternatively,

StringBuilder result = new StringBuilder();
for(String string : collection) {
    result.append(string);
    result.append(',');
}
return result.substring(0, result.length() - 1) ;
樱花落人离去 2024-09-19 10:20:43
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true
淡忘如思 2024-09-19 10:20:43

还有另一种选择:

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

Yet another alternative:

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();
}
浅黛梨妆こ 2024-09-19 10:20:43

为了避免 prefix 的重新初始化(影响性能),请使用 TextUtils.isEmpty:

            String prefix = "";
            for (String item : list) {
                sb.append(prefix);
                if (TextUtils.isEmpty(prefix))
                    prefix = ",";
                sb.append(item);
            }

To avoid reinit(affect performance) of prefix use TextUtils.isEmpty:

            String prefix = "";
            for (String item : list) {
                sb.append(prefix);
                if (TextUtils.isEmpty(prefix))
                    prefix = ",";
                sb.append(item);
            }
抽个烟儿 2024-09-19 10:20:43

您可以尝试使用“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"

You may try to use 'Joiner' class instead of removing the last character from your generated text;

                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"
箜明 2024-09-19 10:20:43

我正在做如下的事情:

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

I am doing something like below:

    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < value.length; i++) {
        stringBuilder.append(values[i]);
        if (value.length-1) {
            stringBuilder.append(", ");
        }
    }
淑女气质 2024-09-19 10:20:43

我发现自己经常这样做,所以我为 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 - 热点26ms40ms26ms
Windows Server 2016、Java 8 - 热点27ms36ms21ms
Windows Server 2016、Java 11 - OpenJ963ms81ms59ms
Windows Server 2016 , Java 8 - OpenJ966ms64ms55ms

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

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

I found myself doing this quite a bit so I wrote a benchmark for the 3 main append delimiter techniques:

(benchmark with proper warmup and 100 rounds of 100,000 iterations)

"Append After"

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

"Append Maybe"

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

I got the following results:

PlatformAppend AfterAppend BeforeAppend Maybe
Windows Server 2016, Java 11 - Hotspot26ms40ms26ms
Windows Server 2016, Java 8 - Hotspot27ms36ms21ms
Windows Server 2016, Java 11 - OpenJ963ms81ms59ms
Windows Server 2016, Java 8 - OpenJ966ms64ms55ms

Aside from being the fastest, I am of the opinion that the "Append Maybe" implementation shows the intent of the code the best. That is usually more important than the fraction of nanoseconds gained per iteration.

I left the benchmark code here in case anyone wanted to try it on their platform. Please contribute your results above if you do so!

江南月 2024-09-19 10:20:43

这是另一个解决方案:

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

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

Here is another solution:

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

String resultingString = "";
if ( sb.length() > 1 ) {
    resultingString = sb.substring(1);
}
夕色琉璃 2024-09-19 10:20:43

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

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

独留℉清风醉 2024-09-19 10:20:43

如果您不想使用 StringJoiner,这是对 @superpupervlad 技术的一个小改进(对于大型列表有很好的增益),它减少了分配的数量。

char prefix = '\0'; // same as ""
for (String serverId : serverIds) {
  sb.append(prefix);
  if (prefix == '\0') prefix = ',';
  sb.append(serverId);
}

If you don't want to use StringJoiner, here's a small improvement on the @superpupervlad technique (with a good gain for large lists), which reduces the number of assignments.

char prefix = '\0'; // same as ""
for (String serverId : serverIds) {
  sb.append(prefix);
  if (prefix == '\0') prefix = ',';
  sb.append(serverId);
}
仙女山的月亮 2024-09-19 10:20:43

更简单和紧凑的解决方案只需要对代码进行少量修改。

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

A much more simple and compact solution just requires a small modification to your code.

for (String serverId : serverIds) {
  if (!sb.isEmpty()) sb.append(",")
  sb.append(serverId);
}
﹉夏雨初晴づ 2024-09-19 10:20:42

其他人指出了 deleteCharAt 方法,但这里有另一种替代方法:

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

或者,使用 Joiner 来自 Guava :)

从 Java 8 开始,StringJoiner 是标准 JRE 的一部分。

Others have pointed out the deleteCharAt method, but here's another alternative approach:

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

Alternatively, use the Joiner class from Guava :)

As of Java 8, StringJoiner is part of the standard JRE.

羁〃客ぐ 2024-09-19 10:20:42

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

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

Another simple solution is:

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

A more complicated solution:

The above solution assumes that sb.length() > 0 ... i.e. there is a "last character" to remove. If you can't make that assumption, and/or you can't deal with the exception that would ensue if the assumption is incorrect, then check the StringBuilder's length first; e.g.

// 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));
一世旳自豪 2024-09-19 10:20:42
if(sb.length() > 0){
    sb.deleteCharAt(sb.length() - 1);
}
if(sb.length() > 0){
    sb.deleteCharAt(sb.length() - 1);
}
三月梨花 2024-09-19 10:20:42

从 Java 8 开始,String 类有一个静态方法 加入。第一个参数是每对字符串之间所需的字符串,第二个参数是 Iterable(它们都是接口,因此类似于 List > 有效,所以你可以这样做:

String.join(",", serverIds);

同样在 Java 8 中,你可以使用新的 StringJoiner 类,适用于您希望在将完整的元素列表放入其中之前开始构造字符串的情况。

As of Java 8, the String class has a static method join. The first argument is a string that you want between each pair of strings, and the second is an Iterable<CharSequence> (which are both interfaces, so something like List<String> works. So you can just do this:

String.join(",", serverIds);

Also in Java 8, you could use the new StringJoiner class, for scenarios where you want to start constructing the string before you have the full list of elements to put in it.

源来凯始玺欢你 2024-09-19 10:20:42

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

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

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

编辑

由于我不断地提出我的答案(谢谢大家

Just get the position of the last character occurrence.

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

Since lastIndexOf will perform a reverse search, and you know that it will find at the first try, performance won't be an issue here.

EDIT

Since I keep getting ups on my answer (thanks folks ????), it is worth regarding that:

On Java 8 onward it would just be more legible and explicit to use StringJoiner.
It has one method for a simple separator, and an overload for prefix and suffix.

Examples taken from here: example

Example using simple separator:

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

Output:

Logan-Magneto-Rogue-Storm

Example with suffix and prefix:

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

Output

(Negan,Rick,Maggie,Daryl)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文