string.substring()越界抛stringindexoutofboundsexception是因为内部显式校验索引范围,不自动修正;安全做法是用math.min限制结束位置、提前判空判长度、归一化索引或使用单参数重载。

String.substring() 越界时为什么抛出 StringIndexOutOfBoundsException
这个异常不是 JVM 随意抛的,而是 substring() 在内部做了显式校验:只要 beginIndex 或 endIndex 超出字符串实际长度(0 ≤ beginIndex ≤ endIndex ≤ str.length()),立刻中断执行。它不尝试“自动截断”或“静默修正”,这是 Java 字符串不可变性和边界安全的设计选择。
常见错误现象:
- 用
str.substring(i, i + 3)处理末尾字符时,i + 3 > str.length()直接崩溃 - 从正则匹配结果取
group(1)后直接切片,但该 group 可能为null或空字符串 - 用户输入含换行,
line.split(" ")[0].substring(5)在短行上失败
如何安全地做字符串切片而不崩
核心思路是把“越界”转为“可控回退”,而不是依赖 try-catch 捕获异常——后者成本高、掩盖逻辑缺陷。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 用
Math.min()限制结束位置:str.substring(i, Math.min(i + 3, str.length())) - 提前判空和长度:
if (str != null && str.length() > i) { ... } - 对不确定来源的索引,先归一化:
int safeStart = Math.max(0, Math.min(i, str.length())) - 如果语义允许“不足就取到末尾”,优先用
substring(beginIndex)单参数重载,它只校验beginIndex,不涉及endIndex越界问题
replaceFirst() 和 split() 的隐性越界风险
这两个方法本身不抛 StringIndexOutOfBoundsException,但它们的返回值常被链式调用 substring(),从而间接触发异常。尤其在处理非预期格式数据时,风险极高。
典型场景:
-
str.replaceFirst("prefix:(\w+)", "$1").substring(0, 5)—— 若原串不含 "prefix:",replaceFirst()返回原串,但原串可能短于 5 -
str.split(":")[1].substring(2)——split()结果数组长度可能为 1,[1]就是ArrayIndexOutOfBoundsException,虽不是字符串异常,但根源相同:没验证切片前提 - 正则捕获组未匹配成功时,
matcher.group(1)返回null,接着调substring()会触发NullPointerException,容易误判为越界
性能与兼容性注意点
Java 9+ 的 substring() 不再共享底层 char[],所以安全包装(如 Math.min)几乎无额外开销;但在 Java 8 及更早版本中,过度使用 substring() 可能导致内存泄漏(大字符串被小子串持引用)。不过,这和越界保护无关,只是顺带提醒:别为了“保险”而无节制切片。
另外,String.charAt() 同样严格校验索引,报的也是 StringIndexOutOfBoundsException,保护方式一致,可复用同一套防御逻辑。
最易被忽略的是:日志里看到这个异常时,很多人只修 substring 调用点,却没追溯上游——那个 i 是从哪来的?是解析 JSON 的字段名长度?还是 HTTP Header 的 value 截断逻辑?根因往往不在字符串操作本身。










