为什么’substring(startIndex,endIndex)’没有抛出“超出范围”

在Java中我使用substring()方法,我不确定为什么它不会抛出“out of index”错误。

字符串abcde索引从0到4开始,但是substring()方法根据我可以调用foo.substring(0)并获取“abcde”的事实将startIndex和endIndex作为参数。

那么为什么子串(5)有效呢? 该指数应该超出范围。 解释是什么?

 /* 1234 abcde */ String foo = "abcde"; System.out.println(foo.substring(0)); System.out.println(foo.substring(1)); System.out.println(foo.substring(2)); System.out.println(foo.substring(3)); System.out.println(foo.substring(4)); System.out.println(foo.substring(5)); 

此代码输出:

 abcde bcde cde de e //foo.substring(5) output nothing here, isn't this out of range? 

当我用6替换5时:

 foo.substring(6) 

然后我得到错误:

 Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1 

根据Java API doc ,当起始索引大于String的Length时,substring会引发错误。

IndexOutOfBoundsException – 如果beginIndex为负或大于此String对象的长度。

事实上,他们举了一个像你的例子:

 "emptiness".substring(9) returns "" (an empty string) 

我想这意味着最好将Java String视为以下内容,其中索引包含在|

 |0| A |1| B |2| C |3| D |4| E |5| 

也就是说字符串同时具有开始和结束索引。

当你执行foo.substring(5) ,它获取从“e”之后的位置开始并在字符串末尾结束的子字符串。 顺便提一下,开始和结束位置恰好相同。 因此,空字符串。 您可以将索引视为字符串中的实际字符,而不是字符之间的位置。

  --------------------- String: | a | b | c | d | e | --------------------- Index: 0 1 2 3 4 5 

我知道这个线程已经很老了,但这是一个基本问题,我认为这值得澄清。

问题是正确的。 我将此视为Java String.substring(int beginIndex,int endIndex)方法中的软件错误。

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#substring%28int,%20int%29

来自Java Docs https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

Java数组

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/我们看到方法定义是:

string substr(size_t pos = 0,size_t len = npos)const;

请注意,方法定义中的第二个参数的长度为“len”。

len要包含在子字符串中的字符数(如果字符串较短,则使用尽可能多的字符)。

testString有10个字符,索引位置为0到9.指定endIndex为10应始终抛出IndexOutOfBoundsException(),因为testString没有endIndex为10。

如果我们使用查看C ++方法的具体值来测试JUnit中的方法,我们期望:

String testString =“testString”; assertThat(testString.substring(4,6),equalTo(“String”));

但当然我们得到预期:“字符串”但是“St”

testString从索引0到’String’中的char’g’的长度是10个字符。 如果我们使用10作为’endIndex’参数,

String 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方法签名应该是:

 public String substring(int beginIndex, int lengthOfSubstringFromIndex0) 

或者重新定义方法以匹配C ++ string :: substr方法。 重新定义当然意味着重写整个互联网,所以不太可能。

来自String API javadoc:

 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. 

例子:

 "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" 

参数:

 beginIndex - the beginning index, inclusive. Returns: the specified substring. Throws: IndexOutOfBoundsException - if beginIndex is negative or larger than the length of this String object. 

====

所以这是设计的。 如果将索引作为字符串的大小,则返回空字符串。

substring(5)指向现有索引…它恰好指向一个空字符串。 另一方面,substring(6)只是疯狂的谈话。 🙂

这是因为substring函数返回一个“包含”子字符串。 因此,索引5指向字符串结尾之前的位置,但是在字符串的最后一个显示字符之后。

这在文档中显示: http : //download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/java/lang/String.html#substring(int)