StringBuilder.substring()
是 StringBuilder
类中用于提取子字符串的方法。它允许你从可变字符序列中截取一部分内容,生成一个不可变的 String
对象。
一、方法定义
StringBuilder
提供了两个重载的 substring()
方法:
方法 1:substring(int start)
public String substring(int start)
- 功能:从索引
start
开始,截取到字符串末尾。 - 参数:
start
- 起始索引(包含),从 0 开始。 - 返回值:一个新的
String
对象,包含从start
到末尾的字符。 - 异常:
StringIndexOutOfBoundsException
- 如果start < 0
或start > length()
。
方法 2:substring(int start, int end)
public String substring(int start, int end)
- 功能:截取从索引
start
到end-1
的字符(左闭右开区间)。 - 参数:
start
- 起始索引(包含)。end
- 结束索引(不包含)。
- 返回值:一个新的
String
对象,包含[start, end)
范围内的字符。 - 异常:
StringIndexOutOfBoundsException
- 如果start < 0
、end < 0
、start > end
或end > length()
。
重要区别:
StringBuilder.substring()
返回String
,而StringBuilder
的其他方法(如append
、replace
)返回StringBuilder
本身。
二、功能说明
- 提取子串:从
StringBuilder
的当前内容中提取指定范围的字符。 - 不可变结果:返回的是
String
对象,内容不可再修改。 - 不修改原对象:调用
substring()
不会改变StringBuilder
本身的值。 - 左闭右开区间:
end
索引不包含在结果中,即[start, end)
。 - 支持边界情况:
start == end
→ 返回空字符串""
。start == length()
→ 返回空字符串""
(仅substring(start)
)。
三、示例代码
示例 1:substring(int start)
基本用法
StringBuilder sb = new StringBuilder("Hello World");
String sub1 = sb.substring(6); // 从索引 6 开始
System.out.println(sub1); // 输出:World
// 索引:H(0) e(1) l(2) l(3) o(4) (5) W(6) o(7) r(8) l(9) d(10)
示例 2:substring(int start, int end)
基本用法
StringBuilder sb = new StringBuilder("Hello World");
String sub2 = sb.substring(0, 5); // [0,5) → 索引 0,1,2,3,4
System.out.println(sub2); // 输出:Hello
示例 3:提取中间部分
StringBuilder sb = new StringBuilder("User: Alice, Age: 25");
String name = sb.substring(6, 11); // [6,11) → "Alice"
String ageStr = sb.substring(18, 20); // [18,20) → "25"
System.out.println("Name: " + name + ", Age: " + ageStr);
// 输出:Name: Alice, Age: 25
示例 4:边界情况
StringBuilder sb = new StringBuilder("Test");
// start == length()
System.out.println(sb.substring(4)); // 输出:""(空字符串)
// start == end
System.out.println(sb.substring(2, 2)); // 输出:""(空字符串)
// end == length()
System.out.println(sb.substring(1, 4)); // 输出:"est"
示例 5:substring()
不修改原对象
StringBuilder sb = new StringBuilder("Original");
String sub = sb.substring(0, 3);
System.out.println("Substring: " + sub); // 输出:Ori
System.out.println("StringBuilder: " + sb.toString()); // 输出:Original(未变)
示例 6:链式调用(注意返回类型)
StringBuilder sb = new StringBuilder("Hello");
// ❌ 错误:substring() 返回 String,没有 append() 方法
// sb.substring(0, 3).append("XXX"); // 编译错误!
// ✅ 正确:先操作 StringBuilder,再取子串
String result = sb.append(" World").substring(6, 11); // "World"
System.out.println(result);
四、使用技巧
技巧 1:快速提取前缀或后缀
StringBuilder sb = new StringBuilder("prefix_data_suffix");
// 提取前缀
String prefix = sb.substring(0, 7); // "prefix_"
// 提取后缀(结合 length)
int len = sb.length();
String suffix = sb.substring(len - 7); // "suffix"(最后 7 个字符)
技巧 2:与 indexOf()
配合提取关键字
StringBuilder sb = new StringBuilder("Error: NULL_POINTER, Code: E001");
int start = sb.indexOf("Code: ") + 6; // 跳过 "Code: "
int end = sb.indexOf(",", start); // 查找下一个逗号
if (end == -1) end = sb.length(); // 如果没有逗号,则到末尾
String errorCode = sb.substring(start, end);
System.out.println("Error Code: " + errorCode); // 输出:E001
技巧 3:安全提取(避免异常)
public static String safeSubstring(StringBuilder sb, int start, int end) {
int len = sb.length();
// 边界修正
start = Math.max(0, Math.min(start, len));
end = Math.max(start, Math.min(end, len));
return sb.substring(start, end);
}
// 使用
StringBuilder sb = new StringBuilder("Hi");
System.out.println(safeSubstring(sb, 0, 10)); // 输出:"Hi"(自动修正 end=2)
技巧 4:提取固定长度字段
// 假设格式:ID(4位)Name(10位)Age(3位)
StringBuilder sb = new StringBuilder("0001Alice 25");
String id = sb.substring(0, 4); // "0001"
String name = sb.substring(4, 14); // "Alice "
String age = sb.substring(14, 17); // "25"
五、常见错误
错误 1:索引越界
StringBuilder sb = new StringBuilder("Hi");
String sub = sb.substring(5);
// 抛出 StringIndexOutOfBoundsException
// 原因:start=5 > length()=2
错误 2:end < start
String sub = sb.substring(3, 1);
// 抛出 StringIndexOutOfBoundsException
错误 3:混淆“包含”与“不包含”
StringBuilder sb = new StringBuilder("Hello");
// 想提取 "llo"(索引 2,3,4),错误写法:
String sub = sb.substring(2, 4); // 只取索引 2,3 → "ll"
// 正确写法:
String correct = sb.substring(2, 5); // 取索引 2,3,4 → "llo"
错误 4:误以为修改了原对象
StringBuilder sb = new StringBuilder("Original");
sb.substring(0, 3); // 返回 "Ori",但 sb 仍是 "Original"
// 如果想修改 sb,需用 replace/delete 等方法
六、注意事项
- 返回
String
:substring()
返回的是新的String
对象,不是StringBuilder
。 - 左闭右开:
end
索引不包含在结果中,务必注意。 - 不修改原对象:
StringBuilder
本身内容不变。 - 性能:创建新
String
对象,涉及内存分配和字符复制。 - 共享字符数组?:与
String
的substring()
不同,StringBuilder.substring()
不会共享内部字符数组,而是创建新数组复制数据(JDK 7+ 行为)。
七、最佳实践
1. 验证索引有效性
int len = sb.length();
if (start >= 0 && start <= len && end >= start && end <= len) {
String result = sb.substring(start, end);
} else {
// 处理边界情况或抛出自定义异常
}
2. 避免不必要的 substring()
- 如果只是想查看部分内容,考虑直接操作
StringBuilder
。 - 频繁提取可能影响性能,评估是否需要缓存结果。
3. 使用 safeSubstring
工具方法
- 在不确定索引时,使用封装的边界安全方法。
4. 理解与 String.substring()
的区别
String.substring()
(JDK 6)曾共享数组导致内存泄漏,JDK 7+ 已修复。StringBuilder.substring()
始终复制数据,无共享风险。
八、总结
要点 | 说明 |
---|---|
核心作用 | 从 StringBuilder 中提取子字符串 |
方法重载 | substring(start) 和 substring(start, end) |
返回类型 | String (新对象,不可变) |
关键规则 | 左闭右开区间 [start, end) |
不修改原对象 | StringBuilder 内容保持不变 |
常见错误 | 索引越界、混淆包含性、误以为修改原对象 |
最佳实践 | 验证索引、安全提取、理解性能开销 |
最终建议:
StringBuilder.substring()
是一个安全、直观的子串提取工具。掌握其“左闭右开”的索引规则是避免错误的关键。在实际开发中,常用于解析固定格式字符串、提取关键字、截取前后缀等场景。记住:它只读取内容,不修改StringBuilder
。结合indexOf()
和边界检查,即可高效、安全地处理各种文本提取需求。