在while循环的终止条件中的StringIndexOutOfBoundsException

时间:2013-02-09 13:07:02

标签: java

我在 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(); 
    }
}

2 个答案:

答案 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 ,因为调用将尝试获取字符串外部。请记住,字符串中的索引是从0length() - 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