提问人:Matthew 提问时间:8/3/2010 最后编辑:Jared BurrowsMatthew 更新时间:11/18/2023 访问量:456504
删除 StringBuilder 的最后一个字符?
Remove last character of a StringBuilder?
问:
当您必须遍历一个集合并用分隔符分隔每个数据的字符串时,您总是会在末尾使用一个额外的分隔符,例如
for (String serverId : serverIds) {
sb.append(serverId);
sb.append(",");
}
给出如下内容:serverId_1、serverId_2、serverId_3、
我想删除 StringBuilder 中的最后一个字符(不转换它,因为在此循环之后我仍然需要它)。
答:
if(sb.length() > 0){
sb.deleteCharAt(sb.length() - 1);
}
评论
separator.length()
另一个简单的解决方案是:
sb.setLength(sb.length() - 1);
更复杂的解决方案:
上述解决方案假设...即有一个“最后一个字符”要删除。如果您无法做出该假设,和/或无法处理假设不正确时随之而来的异常,请首先检查 StringBuilder 的长度;例如sb.length() > 0
// 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));
评论
setLength
ensureCapacityInternal
Arrays.copy
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true
其他人已经指出了这种方法,但这里有另一种替代方法:deleteCharAt
String prefix = "";
for (String serverId : serverIds) {
sb.append(prefix);
prefix = ",";
sb.append(serverId);
}
从 Java 8 开始,StringJoiner
是标准 JRE 的一部分。
评论
Joiner
StringUtils
或者
StringBuilder result = new StringBuilder();
for(String string : collection) {
result.append(string);
result.append(',');
}
return result.substring(0, result.length() - 1) ;
评论
另一种选择:
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();
}
另一种选择
for(String serverId : serverIds) {
sb.append(",");
sb.append(serverId);
}
sb.deleteCharAt(0);
评论
在本例中,
sb.setLength(sb.length() - 1);
是可取的,因为它只将最后一个值赋值,而删除最后一个字符则'\0'
System.arraycopy
评论
setLength
setLength
length
arraycopy
从 Java 8 开始,String 类具有静态方法连接
。第一个参数是每对字符串之间想要的字符串,第二个参数是(它们都是接口,所以类似的东西可以工作。因此,您可以这样做:Iterable<CharSequence>
List<String>
String.join(",", serverIds);
同样在 Java 8 中,您可以使用新的 StringJoiner
类,用于在要放入字符串的完整元素列表之前开始构造字符串的情况。
评论
String.join
StringJoiner
我正在做如下事情:
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < value.length; i++) {
stringBuilder.append(values[i]);
if (value.length-1) {
stringBuilder.append(", ");
}
}
只需获取最后一个字符出现的位置即可。
for(String serverId : serverIds) {
sb.append(serverId);
sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));
由于将执行反向搜索,并且您知道它会在第一次尝试时找到,因此性能在这里不会成为问题。lastIndexOf
编辑
由于我一直在回答我的答案(谢谢大家😊),因此值得一提的是:
在 Java 8 及更高版本上,使用 StringJoiner 会更加清晰和明确。 它有一个用于简单分隔符的方法,以及一个用于前缀和后缀的重载。
取自此处的示例: 示例
使用简单分隔符的示例:
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);
输出
(尼根,瑞克,玛姬,达里尔)
评论
,
for loop
lastInfexOf
你可以使用类的静态方法,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
为了避免使用 TextUtils.isEmpty 的 reinit(影响性能):prefix
String prefix = "";
for (String item : list) {
sb.append(prefix);
if (TextUtils.isEmpty(prefix))
prefix = ",";
sb.append(item);
}
评论
您可以尝试使用“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"
这是另一种解决方案:
for(String serverId : serverIds) {
sb.append(",");
sb.append(serverId);
}
String resultingString = "";
if ( sb.length() > 1 ) {
resultingString = sb.substring(1);
}
评论
stringBuilder.Remove(stringBuilder.Length - 1, 1);
评论
remove
Length
length
我发现自己经常这样做,所以我为 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毫秒 | 81毫秒 | 59毫秒 |
Windows Server 2016,Java 8 - OpenJ9 | 66毫秒 | 64毫秒 | 55毫秒 |
除了速度最快之外,我认为“Append Maybe”实现最能显示代码的意图。这通常比每次迭代获得的纳秒分数更重要。
我把基准测试代码留在这里,以防有人想在他们的平台上尝试。如果您这样做,请在上面提供您的结果!
评论
for
如果您不想使用 StringJoiner
,这里有对 @superpupervlad 技术的一个小改进(对于大型列表有很好的增益),它减少了赋值的数量。
char prefix = '\0'; // same as ""
for (String serverId : serverIds) {
sb.append(prefix);
if (prefix == '\0') prefix = ',';
sb.append(serverId);
}
一个更简单、更紧凑的解决方案只需要对代码进行少量修改。
for (String serverId : serverIds) {
if (!sb.isEmpty()) sb.append(",")
sb.append(serverId);
}
评论
StringJoiner