Substring (startIndex, endIndex) - почему "вне диапазона" не выбрасывается?
В Java я использую метод substring()
, и я не уверен, почему он не выбрасывает ошибку "из индекса".
Строка abcde
имеет начало индекса от 0 до 4, но метод substring()
принимает startIndex и endIndex как аргументы, основанные на том, что я могу вызвать foo.substring(0) и получить "abcde"
Тогда почему работает подстрока (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?
Когда я заменю 5 на 6:
foo.substring(6)
Затем я получаю ошибку:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: -1
Ответы
Ответ 1
В соответствии с Java API doc подстрока выдает ошибку, когда начальный индекс больше длины строки.
IndexOutOfBoundsException - если beginIndex отрицательный или больше, чем длина этого объекта String.
На самом деле они дают пример, похожий на ваш:
"emptiness".substring(9) returns "" (an empty string)
Я предполагаю, что это означает, что лучше всего думать о Java String, как о следующем: где индекс заключен в |
:
|0| A |1| B |2| C |3| D |4| E |5|
То есть строка имеет как начальный, так и конечный индекс.
Ответ 2
Когда вы выполняете foo.substring(5)
, он получает подстроку, начиная с позиции сразу после "e" и заканчивая в конце строки. Кстати, начальная и конечная позиции оказываются одинаковыми. Таким образом, пустая строка. Вы можете думать о том, что индекс не является фактическим символом в строке, а находится между символами.
---------------------
String: | a | b | c | d | e |
---------------------
Index: 0 1 2 3 4 5
Ответ 3
Из строкового 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.
====
Итак, это по дизайну. Если вы укажете индекс как размер строки, он возвращает пустую строку.
Ответ 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 Docs https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
![Java Arrays]()
Java/C/С++ и любой другой язык, о котором я знаю, НЕ рассматривает индекс массива как "разделитель" между элементами массива.
Параметры: beginIndex - начальный индекс, включительно. endIndex - конечный индекс, эксклюзивный.
Либо endIndex неверно назван, потому что язык не разрешает доступ к памяти по адресу endIndex + 1, который должен включать последний элемент массива. OR endIndex не определен и должен быть: endIndex - конечный индекс, включительно.
Наиболее вероятным случаем является то, что второй параметр был неверно назван. Должен быть: length - длина строки, начинающейся с beginIndex.
Мы знаем, что Gosling основывает синтаксис 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.
Если мы протестируем метод в JUnit с конкретными значениями, рассматривая метод С++, мы ожидаем:
Строка testString = "testString";
assertThat (testString.substring(4, 6), equalTo ( "String" ));
но, конечно, мы ожидаем: "String" , но было "St"
Длина testString от индекса 0 до char 'g' в 'String' составляет 10 символов.
Если мы используем 10 в качестве параметра "endIndex",
Строка testString = "testString";
assertThat (testString.substring(4, 10), equalTo ( "String" ));
"Пропустить" из JUnit.
Если мы переименуем параметр 2 в "lengthOfSubstringFromIndex0", вам не нужно делать счет endIndex-1, и он никогда не бросает IndexOutOfBoundsException(), который ожидается при указании endIndex, 10, который выходит за пределы диапазона для базовый массив. http://docs.oracle.com/javase/7/docs/api/java/lang/IndexOutOfBoundsException.html
Это лишь один из тех случаев, когда вы должны помнить об идиосинкразии этого метода. Второй параметр не указан правильно. Подпись метода Java должна быть:
public String substring(int beginIndex,
int lengthOfSubstringFromIndex0)
Или метод переопределен для соответствия методу string: substr С++. Переосмысление, конечно, означало бы переписывание всего Интернета, поэтому это вряд ли.
Ответ 5
Подстрока (5) указывает на существующий индекс... это просто указывает на пустую строку. подстрока (6), с другой стороны, является просто сумасшедшим разговором.:)
Ответ 6
Это потому, что подстрочная функция возвращает подстроку "inclusive". Таким образом, индекс 5 указывает на местоположение до конца строки, но ПОСЛЕ последнего отображаемого символа строки.
Это показано в документации:
http://download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/java/lang/String.html#substring(int)