-3

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

2 回答 2

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 中检查它,并且 count 将增加零。

但更重要的是,在 while 的终止条件下,您的 check ifs.charAt(j)发生在 check 之前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并按下 enter,这意味着InputSream将从键盘读取23\n23是用户输入的数字,\n换行符。使用换行符是为了让计算机知道一行何时结束,下一行何时开始,并在用户按下回车时自动插入。此处提供更多信息:如何获得依赖于平台的换行符?

当您呼叫 时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)). 如果这个词是真的,那么它会评估这个词(k<s.length()),如果这也是真的,它会评估(j<s.length())。如果所有这些条件都为,程序将进入循环。

另一方面,如果第一项(即(s.charAt(j)==s.charAt(k)))为,则整个表达式为(因为我们有AND运算符),并且不需要计算其余项。

现在,为什么会导致Exception?看看最后一次迭代发生了什么。此时,变量j(或k等效)将具有等于 string 长度的值s。当 JVM 试图评估终止条件时,它会首先评估 term (s.charAt(j)==s.charAt(k))。由于j等于 的长度s,因此调用charAt()将抛出StringIndexOutOfBoundsException,因为调用将尝试获取字符串之外的字符。请记住,字符串中的索引是 from 0to length() - 1。这是您获得异常的地方。

但是,如果您将终止条件更改为

((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k)))

您将避免StringIndexOutOfBoundsException。这就是为什么。这一次,术语(k < s.length())和 在调用之前(j < s.length())被评估。因此,当我们到达字符串的末尾时,前两个项中至少有一个是,并且不需要计算表达式的其余部分。因此,在最后一次迭代中,该方法根本没有被调用,所以我们没有得到异常。charAt()falsecharAt

我希望这能稍微澄清一下情况。

于 2013-02-09T13:13:09.470 回答
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
于 2013-02-09T13:12:16.723 回答