为什么substring()方法substring(起始索引(包括),结束索引(独占))

substring将起始参数作为索引,第二个参数作为从头开始的长度的原因是什么?

换一种说法

1 2 3 | 4 5 <=== Length from beginning ABCDE 0 | 1 2 3 4 <=== Index 

如果我想要substring()返回BC我必须做"ABCDE".substring(1,3);

为什么会这样?

编辑:使最终索引独占有什么好处?

关于“为什么”的问题可以被认为是哲学的或学术的,并且沿着“那就是它的方式”的方式挑起答案。

然而,从更一般的抽象观点来看,在考虑替代方案时,这是一个有效的问题:人们可以想象这种方法的两种forms:

 String substringByIndices(int startIndex, int endIndex); 

 String substringByLength(int startIndex, int length); 

在这两种情况下,设计空间都有另一个维度,即指数是包容性的还是排他性的

首先,请注意所有版本基本相同。 在调用站点,根据方法的实际语义更改调用​​通常是微不足道的:

 int startIndex = ...; int endIndex = ...; String s = string.substringByLength(startIndex, endIndex-startIndex); 

要么

 int startIndex = ...; int length = ...; String s = string.substringByIndices(startIndex, startIndex+length); 

选择指数是包容性还是排他性将增加一些潜力,不得不在这里和那里摆弄+1-1 ,但这在这里并不重要。

第二个例子已经说明了为什么选择使用包含起始索引和独占结束索引可能是一个好主意:很容易切出一定长度的子字符串,而不必考虑任何+1-1

 int startIndex = 12; int length = 34; String s = string.substringByIndices(startIndex, startIndex+length); // One would expect this to yield "true". If the end index // was inclusive, this would not be the case... System.out.println(s.length() == length); 

这也可以被认为与你通常拥有的-loops之类for东西一致

 for (int i=startIndex; i 

开始是包容性的 ,结束是独家的 。 因此,这种选择很好地与通常的惯用语言模式相匹配。


但是,无论做出哪种选择,无论其如何合理:重要的是

一贯

贯穿整个API。

例如, List接口包含一个方法subList(int,int) :

 List subList(int fromIndex, int toIndex) 

返回指定fromIndex(包含)和toIndex(独占)之间此列表部分的视图。

与这个惯例一致。 如果你必须混合API,其中结束索引有时是包容性的,有时是独占的,这将容易出错。

这是一个开始和结束索引。

对我来说这似乎很合乎逻辑,但如果您愿意,可以使用一个非常简单的计算来考虑它的起点和长度:

 "ABCDEFGH".substring(start, start + length); 

它为您提供了这种灵活性。

它不是“从一开始的长度”,而是“结束索引独家”。

如果您通过将字符从一个数组复制到另一个数组来查看这两个数字如何与代码一起创建子字符串,原因很明显。

鉴于:

 int start; // inclusive int end; // exclusive char[] string; 

现在看看复制数组元素时使用这些数字是多么容易:

 char[] substring = new char[end - start]; for (int i = start; i < end; i++) substring[i - start] = string[i]; 

注意如何通过加/减1来调整 - 数字正是循环所需的数字。 实际上可以在没有减法的情况下编码循环:

 for (int i = start, j = 0; i < end; i++) substring[j++] = string[i]; 

选择这些数字是“机器友好的”,这是设计C语言的方式,而Java是基于C.

编写代码时的Thumb规则是,从消费者那里获取最大数量或输入。 获得所需的输出变得更容易。

源代码就是答案。 它们都是开始和结束索引。

  public String substring(int beginIndex, int endIndex) { 1942 if (beginIndex < 0) { 1943 throw new StringIndexOutOfBoundsException(beginIndex); 1944 } 1945 if (endIndex > count) { 1946 throw new StringIndexOutOfBoundsException(endIndex); 1947 } 1948 if (beginIndex > endIndex) { 1949 throw new StringIndexOutOfBoundsException(endIndex - beginIndex); 1950 } 1951 return ((beginIndex == 0) && (endIndex == count)) ? this : 1952 new String(offset + beginIndex, endIndex - beginIndex, value); 1953 } 

简单来说,只是提到你想要将其分组的地方。