Why is “out of range” not thrown for 'substring(startIndex, endIndex)'
在Java中,我正在使用
字符串
那么为什么substring(5)起作用? 该索引应超出范围。 有什么解释?
1 2 3 4 5 6 7 8 9 10 11 |
此代码输出:
1 2 3 4 5 6 | abcde bcde cde de e //foo.substring(5) output nothing here, isn't this out of range? |
当我用6替换5时:
1 | foo.substring(6) |
然后我得到错误:
1 2 |
根据Java API文档,当起始索引大于字符串的长度时,子字符串将引发错误。
IndexOutOfBoundsException - if
beginIndex is negative or larger than
the length of this String object.
实际上,它们提供了一个与您非常相似的示例:
1 | "emptiness".substring(9) returns"" (an empty string) |
我想这意味着最好将Java String视为以下内容,其中将索引包装在
1 | |0| A |1| B |2| C |3| D |4| E |5| |
也就是说,字符串同时具有开始索引和结束索引。
当您执行
1 2 3 4 |
我知道这个线程已经很老了,但是这是一个根本性的问题,我认为需要澄清。
这个问题是正确的。我将此视为Java String.substring(int beginIndex,int endIndex)方法中的软件故障。
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring%28int,%20int%29。
从Java文档https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
Java / C / C ++和我所知道的所有其他语言都不会将数组索引视为数组元素之间的"分隔符"。
参数:
beginIndex-起始索引(含)。
endIndex-结束索引(不包括)。
endIndex的名称错误,因为该语言不允许内存访问endIndex + 1处的地址(包括最后一个数组元素),或者endIndex定义不正确,并且必须为:
endIndex-结束索引(含)。
最可能的情况是第二个参数的名称错误。它应该是:
length-从beginIndex开始的所需字符串的长度。
我们知道,出于熟悉的目的,Gosling基于C / C ++语言编写了Java语法。从C ++字符串类http://www.cplusplus.com/reference/string/string/substr/中,我们看到方法定义为:
字符串substr(size_t pos = 0,size_t len = npos)const;
请注意,方法定义中的第二个参数的长度为'len'。
伦
子字符串中包含的字符数(如果字符串较短,则使用尽可能多的字符)。
testString有10个字符,索引位置为0到9。将endIndex指定为10总是应抛出IndexOutOfBoundsException(),因为testString的endIndex不为10。
如果我们使用查看C ++方法的具体值在JUnit中测试该方法,则我们期望:
字符串testString =" testString";
assertThat(testString.substring(4,6),equalTo(" String")));
但是我们当然得到了期望:" String",但是是" St"
testString从索引0到'String'中char'g'的长度为10个字符。
如果我们使用10作为" endIndex"参数,
字符串testString =" testString";
assertThat(testString.substring(4,10),equalTo(" String")));
来自JUnit的"通过"。
如果我们将参数2重命名为" lengthOfSubstringFromIndex0",则不必执行endIndex-1计数,并且它永远不会抛出在指定endIndex 10(超出基础数组范围)时期望的IndexOutOfBoundsException()。 http://docs.oracle.com/javase/7/docs/api/java/lang/IndexOutOfBoundsException.html
这只是您必须记住此方法的特质的一次。第二个参数的名称不正确。 Java方法签名应为:
1 2 |
或者重新定义该方法以匹配C ++ string :: substr方法。当然,重新定义将意味着重写整个Internet,因此不太可能。
从String API javadoc:
1 2 3 4 5 6 7 8 9 10 | public String substring(int beginIndex) Returns a new string that is a substring of this string. The substring begins with the"" character at the specified index and extends to the end of this string. public String substring(int beginIndex, int endIndex) Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex. |
例子:
1 2 3 4 5 6 | "unhappy".substring(2) returns"happy" "Harbison".substring(3) returns"bison" "emptiness".substring(9) returns"" (an empty string) "hamburger".substring(4, 8) returns"urge" "smiles".substring(1, 5) returns"mile" |
参数:
1 2 3 4 5 6 | beginIndex - the beginning index, inclusive. Returns: the specified substring. Throws: IndexOutOfBoundsException - if beginIndex is negative or larger than the length of this String object. |
====
因此,这是设计使然。如果将索引作为字符串的大小,则它将返回空字符串。
这是因为子字符串函数返回一个"包含"子字符串。因此,索引5指向字符串末尾之前但字符串最后显示字符之后的位置。
这在文档中显示:
http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/java/lang/String.html#substring(int)
substring(5)指向一个现有索引...它恰好指向一个空字符串。另一方面,substring(6)只是个疯狂的话题。 :)