我在 while循环的终止条件中得到 StringIndexOutOfBoundsException 。有人能解释一下这个原因吗?
import java.util.Scanner;
class Solution {
public static int fun(String s) {
int count=0;
int k,j;
for(int i=0;i<s.length();i++) {
k=i;
j=0;
if (s.charAt(j) == s.charAt(k)) {
while((s.charAt(j)==s.charAt(k))&&(k<s.length())&&(j<s.length())) {
j++;
k++;
}
count+=j;
}
}
return count;
}
public static void main(String[] args) {
Scanner se=new Scanner(System.in);
int t=se.nextInt();
String s;
int a[]=new int[t];
for(int i=0;i<t;i++) {
s=se.nextLine();
a[i]=fun(s);
}
for(int i=0;i<t;i++)
System.out.println(a[i]);
se.close();
}
}
答案 0 :(得分:2)
来自JavaDoc
的java.lang 类 StringIndexOutOfBoundsException
按String方法抛出,以指示索引为负数 或大于字符串的大小。对于某些方法,如 charAt方法,当索引相等时也抛出此异常 到字符串的大小。
你超过了字符串的长度。
另外我认为你的逻辑中有一些错误(见下文)。
你真正想做的是:
while ((k < s.length()) && (j < s.length())) { // While no String goes out of Bounds
if (s.charAt(j) != s.charAt(k)) { // If we get a different character
break; // Get out of the loop
} else {
j++; // Advance one position
k++;
}
}
你在做什么是这样的:
if (s.charAt(j) == s.charAt(k)) { // If the characters are equal
while ((s.charAt(j) == s.charAt(k)) // While the characters are equal
&& (k < s.length()) && (j < s.length())) { // And the position is smaller than the length
j++;
k++;
}
count += j;
}
If是多余的,因为你无论如何都要用它来咀嚼,而且数量会增加零。
但更重要的是,在while的终止条件下,您可以检查s.charAt(j)
是否在支票j < s.length()
之前发生。因此,在您看到j是否为大
另外,由于表达式是Java从左到右计算,你可以改变你的循环:
while ((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k))) {
j++;
k++;
}
现在你没有得到异常,因为如果前两个术语是假的(从左边开始),那么右边的另外两个术语将不会被评估(至少在我的JVM中)
输出:
run:
2
ababaa
aa
11
3
希望有所帮助。
Ps:我也改变了行
int t = se.nextInt();
到
int t = se.nextInt();se.nextLine();
这样你就可以在给出数字之后解析换行符。
<强> 澄清 强>
1)为什么se.nextLine()
你有
int t = se.nextInt();
假设用户输入23
并按输入,这意味着 InputSream 将从键盘23\n
读取。 23
是用户输入的号码,\n
是换行符字符。使用换行符字符,以便计算机可以判断一行何时结束并且下一行开始,并在用户按Enter键时自动插入。更多信息:How do I get a platform-dependent new line character?
当您致电nextInt()
时,您只会阅读输入的号码,但不会阅读\n
字符。因此,下次拨打readLine()
时,您将阅读输入号码时留下的\n
(并按下回车键)。这就是您将上述命令更改为
int t = se.nextInt();se.nextLine();
现在你读了额外的\n
字符,并且当你读取用户输入的字符串时会发生nextLine()
的下一次调用,将正确返回字符串。
2)为什么要将循环更改为((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k))
你有这个
( (s.charAt(j)==s.charAt(k)) && (k<s.length()) && (j<s.length()) )
这导致 StringIndexOutOfBoundsException 。这就是为什么:
在Java中,表达式从左到右计算。这意味着,在每次迭代时,JVM将首先检查(s.charAt(j)==s.charAt(k))
。如果术语 true ,那么它将评估术语(k<s.length())
,如果这也是 true ,它将评估(j<s.length())
。如果所有这些术语都是 true ,程序将进入循环。
另一方面,如果第一个术语(即(s.charAt(j)==s.charAt(k))
) false ,则整个表达式为 false (因为我们有和 AND 运算符),无需计算其余的术语。
现在,为什么会导致异常?看看最后一次迭代会发生什么。此时,变量j
(或等效的k
)的值将等于字符串s
的长度。当JVM尝试评估终止条件时,它将首先评估术语(s.charAt(j)==s.charAt(k))
。由于j
等于s
的长度,因此调用charAt()
将抛出 StringIndexOutOfBoundsException ,因为调用将尝试获取字符串外部。请记住,字符串中的索引是从0
到length() - 1
。这是你得到异常的地方。
但是,如果您将终止条件更改为
((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k)))
您将避免 StringIndexOutOfBoundsException 。这就是原因。这次,(k < s.length())
和(j < s.length())
在调用charAt()
之前评估。因此,当我们到达字符串的末尾时,两个第一个项中的至少一个将是false
,并且不需要评估表达式的其余部分。因此,在最后一次迭代中,根本没有调用方法charAt
,所以我们没有得到异常。
我希望这有点澄清了这个情况。
答案 1 :(得分:1)
试试这个
for(int i=0;i<t;i++)
{
s=se.nextLine();
se.next(); //add this to discard the newline char of nextLine(). because of newline your next string input is empty string. which leads to IOB exception.
a[i]=fun(s);
}
输出:
2
asdf
asdf
0
0