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

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
4b9b3361

Ответ 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)