From JavaDoc
java.lang
Class StringIndexOutOfBoundsException
Thrown by String methods to indicate that an index is either negative
or greater than the size of the string. For some methods such as the
charAt method, this exception also is thrown when the index is equal
to the size of the string.
You are exceeding the length of the string.
In addition I think you have some errors in your logic (see below).
What you really are trying to do is this:
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++;
}
}
What you were doing was this:
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;
}
The If is redundant, since you chech it in the while anyway, and count would be increased by zero.
But more importantly, in the terminating condition of the while, you the check if s.charAt(j)
happens before the check j < s.length()
. Thus, you get the exception at the first case, before you see if j is to large
In addition, since the expressions is Java are calculated from left to right, you could change your loop like this:
while ((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k))) {
j++;
k++;
}
Now you don't get an Exception, because if the first 2 terms are false (from the left), then the other two term on the right will not be evaluated at all (at least in my JVM)
Output:
run:
2
ababaa
aa
11
3
Hope that helped.
Ps: I also changed the line
int t = se.nextInt();
to
int t = se.nextInt();se.nextLine();
So that you parse the newline after the number is given.
Clarifications
1) Why se.nextLine()
You had
int t = se.nextInt();
Lets say the user enters 23
and presses enter, which means that the InputSream whill read from the keyboard 23\n
. 23
is the number that the user entered, and \n
is newline character. The newline character is used so that the computer can tell when one line ends and the next one begins, and it is automatically inserted when the user presses enter. More info here: How do I get a platform-dependent new line character?
When you call nextInt()
, you only read the number that was entered, but you do not read the \n
character. Thus, next time you call readLine()
, you will read the \n
that is left over from when you entered the number (and pressed enter). This is the reason you change the above command to
int t = se.nextInt();se.nextLine();
Now you read that extra \n
character, and the next call of nextLine()
, that will happen when you read the string that the user entered, will correctly return the string.
2) Why did whe change the loop to ((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k))
You had this
( (s.charAt(j)==s.charAt(k)) && (k<s.length()) && (j<s.length()) )
This caused the StringIndexOutOfBoundsException. And here is why:
In Java, the expressions are calculated from left to right. that means, that at each iteration, the JVM will first check (s.charAt(j)==s.charAt(k))
. If the term is true, then it will evaluate the term (k<s.length())
, and if that is also true, it will evaluate (j<s.length())
. If all these terms are true, the program will enter the loop.
On the other hand, if the first term (i.e. (s.charAt(j)==s.charAt(k))
) is false, then the whole expression is false (since we have and AND operator), and there is no need to calculate the rest of terms.
Now, why did that cause an Exception? Look at what happens at the last iteration. At this point, the variable j
(or k
equivalently) will have a value equal to the length of string s
. When the JVM tries to evaluate the termination condition, it will first evaluate the term (s.charAt(j)==s.charAt(k))
. Since j
is equal to the length of s
, the call charAt()
will throw a StringIndexOutOfBoundsException, since the call will try to get a character that is outside of the string. Remember that the indexes in the String are from 0
to length() - 1
. This is where you got your Exception.
If however, you change the termination condition to
((k < s.length()) && (j < s.length()) && (s.charAt(j) == s.charAt(k)))
you will avoid the StringIndexOutOfBoundsException. Here is why. This time, the terms (k < s.length())
and (j < s.length())
are evaluated before the call to charAt()
. Thus, when we reach the end of the string, at least one of the two first terms will be false
, and there is no need to evaluate the rest of the Expression. Thus, at the last iteration, the method charAt
is not called at all, so we don't get the Exception.
I hope this clarified the situation a bit.