Java拼接字符串删除大写字母时触发索引越界异常问题咨询
问题描述
我尝试将一个字符串与其自身拼接,再从生成的结果字符串中移除所有大写字母。
以下是我编写的实现代码:
public String removeCapitals(String A) { StringBuilder B = new StringBuilder(A+A); int n = B.length(); for(int i=0; i<n; i++){ if(B.charAt(i)>='A' && B.charAt(i)<='Z'){ B.deleteCharAt(i); } } return B.toString(); }
运行代码时抛出如下异常信息:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6 at java.lang.AbstractStringBuilder.charAt(AbstractStringBuilder.java:237) at java.lang.StringBuilder.charAt(StringBuilder.java:76) at Solution.removeCapitals(Solution.java:10) at Main.main(Main.java:190)
问题根本原因
抛出索引越界的核心原因有两个:
- 循环上界写死了初始长度
n,但每次调用deleteCharAt()删除字符时,StringBuilder的实际长度会实时减1,不会保持初始的n不变。当删掉若干个大写字母后,字符串实际长度已经远小于n,这时候循环继续执行到i接近n的值,去访问已经不存在的索引位置,就会直接抛出索引越界异常。 - 这个写法还有个隐藏bug:删除字符后,后续所有字符都会向前移动1位,但循环变量i还是照常递增,会直接跳过原本在被删字符后面、现在挪到当前i位置的字符,就算不触发越界,也会出现大写字母漏删的问题。
举个简单的复现例子:假设传入A是"AbC",拼接后初始字符串是"AbCAbC",初始n=6。遍历到i=2时检测到大写'C',执行删除后字符串长度变成5,再往后遍历删几个字符,等i增长到6的时候,字符串实际长度可能只剩4、5,访问索引6自然报错。
修复方案
给三个可直接运行的改法:
- 方法1:倒序遍历,从后往前删,这样删除操作不会影响还没遍历到的前面的索引位置
public String removeCapitals(String A) { StringBuilder B = new StringBuilder(A+A); for(int i = B.length() - 1; i >= 0; i--){ if(B.charAt(i) >= 'A' && B.charAt(i) <= 'Z'){ B.deleteCharAt(i); } } return B.toString(); }
- 方法2:正序遍历,删除字符后手动让i回退1位,抵消字符前移和i自增的影响,同时不要用固定的n当循环上界,每次取实时长度
public String removeCapitals(String A) { StringBuilder B = new StringBuilder(A+A); for(int i=0; i<B.length(); i++){ if(B.charAt(i)>='A' && B.charAt(i)<='Z'){ B.deleteCharAt(i); i--; // 删完回退,避免跳过字符 } } return B.toString(); }
- 方法3:不用手动遍历,直接用正则替换,代码最简洁
public String removeCapitals(String A) { return (A + A).replaceAll("[A-Z]", ""); }
内容的提问来源于stack exchange,提问作者sai venkat
相关产品推荐
相关产品推荐

