删除StringBuilder的最后一个字符?

Mat*_*hew 391 java stringbuilder

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

for (String serverId : serverIds) {
  sb.append(serverId);
   sb.append(",");
}
Run Code Online (Sandbox Code Playgroud)

给出类似:serverId_1,serverId_2,serverId_3,

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

Jon*_*eet 598

其他人已经指出了这种deleteCharAt方法,但这是另一种替代方法:

String prefix = "";
for (String serverId : serverIds) {
  sb.append(prefix);
  prefix = ",";
  sb.append(serverId);
}
Run Code Online (Sandbox Code Playgroud)

或者,使用GuavaJoiner课程:)

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

  • 不会执行prefix =","; 每个循环周期都影响性能? (29认同)
  • @Harish:可能是一小部分 - 虽然不太可能显着. (20认同)
  • @Coronatus:不,因为""是任何字符的*缺席*,而不是单个字符. (7认同)
  • Apache Commons在他们的`StringUtils`中确实有另一种替代Guava的`Joiner`.http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html#join(java.lang.Object [],java.lang.String) (6认同)
  • @Harish - 如果优化器展开第一个循环迭代,可能根本没有. (4认同)
  • @Bane我同意`deleteCharAt()`方法比Jon Skeet提供的聪明方法更具可读性.也就是说,他的第二个建议可能是最具可读性的.整个事情变成了加入者:`Joiner joiner = Joiner.on(",").useForNull("null");`然后像这样使用它:`String result = joiner.join(serverIds);`. (2认同)
  • @JonSkeet - 聪明.我很想知道是什么引导你这么想的.这是一个想法,还是你花了几秒钟来推理它.我可以想象你可能会这样想过 - 让我们尝试打印,a,b,c这样最后就没有逗号了.现在,我如何摆脱第一个逗号?如果第一个逗号什么都没有呢?但是,在第一次迭代之后,我希望没有什么可以变成逗号.因此我的代码......有道理吗? (2认同)
  • @BoratSagdiyev:老实说,我怀疑我看到其他人这样做了。抱歉没有更鼓舞人心! (2认同)
  • @AntoineMartin:不,这不会在每次迭代时创建新字符串。无需预先添加额外的变量来尝试微优化。 (2认同)

Ste*_*n C 395

另一个简单的解决方案

sb.setLength(sb.length() - 1);
Run Code Online (Sandbox Code Playgroud)

更复杂的解决方案:

上述解决方案假设sb.length() > 0...即要删除"最后一个字符".如果你不能做出这个假设,和/或你不能处理如果假设不正确会发生的异常,那么首先检查StringBuilder的长度; 例如

// Readable version
if (sb.length() > 0) {
   sb.setLength(sb.length() - 1);
}
Run Code Online (Sandbox Code Playgroud)

要么

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

  • 很好的解决方案.性能影响最小,所需代码最少:) (22认同)
  • @ManuJose - 仔细阅读代码。如果“setLength”正在减少长度,“ensureCapacityInternal”将不会调用“Arrays.copy”。(我正在查看 Java 11 代码,但我认为这适用于所有版本。) (2认同)

bra*_*boy 169

sb.deleteCharAt(sb.length() - 1) 
Run Code Online (Sandbox Code Playgroud)

  • 这得到了太多但但效率不高,它确实是system.arraycopy.什么@Rohit Reddy Korrapolu说. (31认同)
  • 对于`sb.length()== 0`也是不安全的 (12认同)

Art*_*are 58

从Java 8开始,String类有一个静态方法join.第一个参数是你想要在每对字符串之间的字符串,第二个参数是一个Iterable<CharSequence>(它们都是接口,所以类似于List<String>工作.所以你可以这样做:

String.join(",", serverIds);
Run Code Online (Sandbox Code Playgroud)

同样在Java 8中,您可以使用新StringJoiner类,以便在您拥有要放入的完整元素列表之前开始构建字符串.


Reu*_*iro 36

只需获取最后一个字符出现的位置.

for(String serverId : serverIds) {
 sb.append(serverId);
 sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));
Run Code Online (Sandbox Code Playgroud)

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


小智 34

在这种情况下,

sb.setLength(sb.length() - 1);
Run Code Online (Sandbox Code Playgroud)

是最好的,因为它只是指定最后一个值,'\0'而删除最后一个字符System.arraycopy

  • _如果newLength参数大于或等于当前长度,则会附加足够的空字符('\ u0000'),以便length成为newLength参数._不是这种情况. (2认同)

Cod*_*roc 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

OUTPUT

James,Harry,Roy
Run Code Online (Sandbox Code Playgroud)


Raf*_*fiq 10

另一种选择

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
sb.deleteCharAt(0);
Run Code Online (Sandbox Code Playgroud)

  • 应该比删除最后一个char更好,因为这需要大小计算.除非删除第一个char导致数据被移动... (2认同)

Zak*_*aki 8

或者,

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


Ant*_*ine 5

StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true
Run Code Online (Sandbox Code Playgroud)


Jas*_*Day 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();
}
Run Code Online (Sandbox Code Playgroud)