-3

I get a StringIndexOutOfBoundsException in the terminating condition of my while loop. Could someone explain the reason for this?

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(); 
    }
}
user000001
  • 32,226
  • 12
  • 81
  • 108
saimadan
  • 13
  • 2
  • 1
    What's the problem? What's the job of this program? What's some input, output and expected output? – leemes Feb 09 '13 at 13:08
  • actually this is a problem from interview street https://www.hackerrank.com/challenges/string-similarity – saimadan Feb 09 '13 at 13:13
  • @saimadan check my ans. if your rest of the logic is correct then you are done with the exception.. – Arpit Feb 09 '13 at 13:14
  • hey @arpit please help me with my logic i don't want to see others code – saimadan Feb 09 '13 at 13:19
  • @saimadan try yourself ! if you get any error in your code, google it and still don't get it then you can use SO. No help for logic. i don't know what the ques. is. – Arpit Feb 09 '13 at 13:23
  • @Arpit say me where the error is happening in the code i googled, i tried, i did a lot of things don't help me with the logic help me with the error – saimadan Feb 09 '13 at 13:27
  • It is easier for the people here to give you answers, if you actually either give the exact error message (if there is one), or describe the error. Also you migth try to describe what this block of code is supposed to do. – scones Feb 09 '13 at 13:30
  • check out this link for he question https://www.hackerrank.com/challenges/string-similarity – saimadan Feb 09 '13 at 13:31
  • @saimadan I added more details to the answer. I hope this clarified the situation for you – user000001 Feb 10 '13 at 18:04

2 Answers2

2

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.

Community
  • 1
  • 1
user000001
  • 32,226
  • 12
  • 81
  • 108
1

try this

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);
    }   

Output:

2
asdf
asdf
0
0
Arpit
  • 12,767
  • 3
  • 27
  • 40