Подтвердить что ты не робот

Почему из индекса включен, но конечный индекс является исключительным?

В методах API Java, например:

  • String.substring(int beginIndex, int endIndex)
  • String.subSequence(int beginIndex, int endIndex)
  • List.subList(int fromIndex, int toIndex)

Почему начальный индекс включен, но эксклюзивный индекс? Почему они не должны были разрабатываться как включительно?

4b9b3361

Ответ 1

Потому что:

  • Java основана на C, и C делает это так.
  • Это делает очиститель кода: если вы хотите захватить до конца объекта, пройдите object.length (однако объект реализует это, например, size() и т.д.) в параметр toIndex - нет необходимости добавлять/вычитать 1

Например:

String lastThree = str.substring(str.length() - 3, str.length());

Таким образом, очень очевидно, что происходит в коде (хорошая вещь).

EDIT Пример функции C, которая ведет себя так: strncat из string.h:

char *strncat(char *dest, const char *src, size_t n);

Значение параметра size_t соответствует параметру java endPosition в том, что они оба являются длиной объекта, но считая от 0, если они являются индексом, это будет один байт за пределами объекта.

Ответ 2

Проблема заключается в том, что они не использовали синтаксис C/С++. Я думаю, что синтаксис C более читабельен. Например, если вы хотите взять подстроку с длиной 2, начиная с третьего элемента списка X, вы пишете

X.subList(2,3).

В Java, если вы хотите сделать подсписку ТОЛЬКО третьим элементом списка X, вам нужно написать X.subList(2,3). Это действительно уродливо, кажется, что вы берете подсписку из двух элементов. С другой стороны, X.subList(2,2) - пустой список - довольно запутанный.

int startIndex = calculateStartIndex();
int endIndex = calculateEndIndex();
X.subList(startIndex, endIndex);

Собственно, если (startIndex == endIndex) → пустой список.

Ваш вопрос: почему, так вот мой ответ. Что произойдет, если оба параметра в Java будут включены? у вас возникнет проблема, когда вам нужно взять пустой список, если вы вычислите второй индекс. Потому что в большинстве случаев индексы вычисляются и мы не записываем непосредственно числа в функции.

Для того, чтобы иметь пустой список, если вы не используете собрание (например: в случае отрицательного или нижнего endIndex возвращают пустой список), - но такая конвенция может скрыть ошибки в кодировании (нет разницы, если второй параметр - 1 или -100!):

int startIndex = calculateStartIndex(); // return 0
int endIndex = calculateEndIndex();     // return 0
X.subList(startIndex, endIndex);        // this would return the 1st element of the list; how to get an empty list? Convenction needed!
                                        // use a negative number to get empty list? And what if endIndex is negative because of a bug?

В этом случае C побеждает; более читабельными в любом случае, жаль, что они изменили это. Но это всего лишь дополнительный комментарий, который вы можете использовать.

Ответ 3

Он называется соглашением Dijkstra диапазонов [i, j> (или в другой математической нотации [i, j)). Таким образом вы можете иметь дело с диапазонами [a, b>, [b, c>, [c, d].

Утверждалось, что он несколько эффективнее, и на самом деле мы его программисты используют в:

for (int i = 0; i < n; ++i) { ... }

В таких диапазонах число элементов j - i, поэтому да сохраняется -1/+ 1.

Он также используется в BitSet.set(from, to)

Ответ 4

В дополнение к тому, что сказал Богем:

Если это было эксклюзивно, чтобы получить первые 4 символы в String, вам нужно:

String firstFour = String.substring(0, 3);

Это довольно уродливо.