stringbuilder.delete(int start, int end)删除从索引start(含)到end(不含)的字符,左闭右开区间,原地修改并返回this。

StringBuilder.delete 方法到底删的是哪一段?
delete 不是“按字符内容删”,而是“按索引范围删”——它从起始索引 start(含)删到结束索引 end(不含)。这点和 substring 一致,但和 remove 或正则替换逻辑完全不同。误以为它能按值删除(比如删掉所有 'a'),就会白忙活。
常见错误现象:sb.delete('a', 'z') 编译不过;sb.delete(0, sb.length()) 想清空却只删了一半——因为 end 超出当前长度时会自动截断为 length(),但若你没检查长度变化,后续操作就可能越界。
- 索引从 0 开始,
end必须 ≥start,否则抛StringIndexOutOfBoundsException - 若
start >= length(),不报错但无任何效果 - 若
end > length(),实际等效于delete(start, length())
想删指定字符(比如所有空格)怎么办?
delete 本身不支持条件删除,必须手动定位索引。最常用且安全的做法是**倒序遍历 + deleteCharAt**,避免索引偏移问题。用 delete 配合 indexOf 也可以,但要注意每次删除后剩余字符的索引已变。
例如删掉所有半角空格:
StringBuilder sb = new StringBuilder("a b c ");
int i = sb.length() - 1;
while (i >= 0) {
if (sb.charAt(i) == ' ') {
sb.deleteCharAt(i);
}
i--;
}
- 不能正序删:删掉位置 2 的空格后,原位置 3 的字符移到 2,下次循环就跳过了
- 别用
delete(i, i+1)替代deleteCharAt(i):语义不清,且多一次边界计算 - 如果要删连续子串(如 "TODO:"),用
indexOf+delete更直接
delete 和 setLength(0)、replace 的性能差别在哪?
三者都不创建新对象,但行为和适用场景不同:setLength(0) 是最快清空方式;replace(0, length(), "") 效果相同但多一次字符串参数处理;delete(0, length()) 语义最清晰,JVM 对它的优化也足够好。
- 清空整个 StringBuilder:优先用
setLength(0),它不检查内容,纯指针重置 - 删中间某段:只能用
delete(start, end),没有替代方案 - 替换成其他内容:用
replace(start, end, str),比delete+insert少一次数组拷贝 - 注意:
delete后capacity()不变,内存未释放;真要缩容得调trimToSize()
为什么删完发现字符还在?常见陷阱
最常被忽略的是:调用 delete 后忘记检查返回值——它返回的是 this,但很多人写成 sb.delete(...).toString() 却没接住新引用,或者误以为它返回新对象。
-
delete是原地修改,返回this主要为了链式调用,不是创建副本 - 如果在循环中反复
delete,记得每次调用前确认当前length(),尤其当end是动态算出来的 - 多线程环境下
StringBuilder非线程安全,delete过程中被其他线程修改会导致不可预测结果
真正难的不是记住语法,是每次调用前心里清楚当前字符串长什么样、索引怎么映射、删完之后其他变量还是否有效。这些细节不写日志、不打断点,很容易漏掉。










