Why is “out of range” not thrown for 'substring(startIndex, endIndex)'

后端 未结 6 992
生来不讨喜
生来不讨喜 2020-11-27 08:02

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

6条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-27 08:26

    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 Arrays

    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.

提交回复
热议问题