In Java I am using the substring()
method and I\'m not sure why it is not throwing an \"out of index\" error.
The string abcde
has index st
I know this thread is quite old but this is such a fundamental problem that I think it warrants clarification.
The question is properly spot on. I view this as a software fault in the Java String.substring(int beginIndex, int endIndex) method.
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring%28int,%20int%29.
From the Java Docs https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
Java/C/C++ and every other language that I know of does NOT view the array index as the 'divider' between array elements.
Parameters: beginIndex - the beginning index, inclusive. endIndex - the ending index, exclusive.
Either endIndex is misnamed because the language does not allow memory access to the address at endIndex + 1 which is required to include the last array element OR endIndex is mis-defined and must be: endIndex - the ending index, inclusive.
The most likely case is that the second parameter was misnamed. It should be: length - the length of the string desired beginning at beginIndex.
We know that Gosling based the Java syntax on the C/C++ languages for familiarity. From C+++ string class http://www.cplusplus.com/reference/string/string/substr/ we see the method definition is:
string substr (size_t pos = 0, size_t len = npos) const;
Note that the second parameter in the method definition is 'len' for length.
len Number of characters to include in the substring (if the string is shorter, as many characters as possible are used).
testString has 10 chars, index positions 0 to 9. Specifying an endIndex of 10 should always throw the IndexOutOfBoundsException() because testString has no endIndex of 10.
If we test the method in JUnit with concrete values looking at the C++ method, we expect:
String testString = "testString"; assertThat(testString.substring(4, 6), equalTo("String"));
but of course we get Expected: "String" but was "St"
The length of testString from index 0 to char 'g' in 'String' is 10 chars. If we use 10 as the 'endIndex' parameter,
String testString = "testString"; assertThat(testString.substring(4, 10), equalTo("String"));
"Pass" from JUnit.
If we rename parameter 2 to "lengthOfSubstringFromIndex0" you don't have to do the endIndex - 1 count, and it never throws the IndexOutOfBoundsException() that is expected when specifying an endIndex, 10, that is out of range for the underlying array. http://docs.oracle.com/javase/7/docs/api/java/lang/IndexOutOfBoundsException.html
This is just one of those times that you have to remember the idiosyncrasy of this method. The second parameter is not named correctly. The Java method signature should be:
public String substring(int beginIndex,
int lengthOfSubstringFromIndex0)
Or the method redefined to match C++ string::substr method. Redefining of course would mean rewriting the entire internet, so it's not likely.