for (int i = 0; i < value.length(); i++) {
char currChar = value.charAt(i);
... // i ниже не изменяется
}
...
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
Логично выбросить проверку из charAt, зачем она нужна? Делают ли это современные JIT'ы для подобных ситуаций? Более того, подгружаясь в код стандартных классов подобных проверок +100500... И я как понимаю, под капотом, к этим проверкам добавляется проверка на выход индекса за границы массива. Т.е. в данном месте:
return value[index];
Докидывается еще одна невидимая проверка с выбросом ArrayIndexOutOfBoundsException. Это безобразие и правда попадает в рантайм? Или современные JIT'ы выкидывают большую часть подобных перепроверок для стандартных классов типа String, ArrayList и т.д.?
Логично выбросить проверку из charAt, зачем она нужна? Делают ли это современные JIT'ы для подобных ситуаций?
Да. После инлайна будут очевидные инварианты. В более сложных случаях может и не убрать. Стандартные классы тут не при чём, JIT про них ничего не знает и не может знать, т.к. тебе ничего не мешает подсунуть модифицированную стандартную библиотеку.
Логично выбросить проверку из charAt, зачем она нужна?
Барьер абстракций (SICP): завтра сделают, что value внутри String'а будет хранить Unicode code point'ы (int), а не char'ы и реализация charAt станет какой-то такой (очень упрощённо):
public final class Utf32String implements CharSequence {
private final int[] codePoints;
private final int charCount;
public Utf32String(String oldString) {
codePoints = oldString.codePoints().toArray();
charCount = str(codePoints).length();
}
@Override
public char charAt(int index) {
if (index < 0 || index >= charCount) {
throw new StringIndexOutOfBoundsException(index);
}
return str(codePoints).charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
// some implementation
return null;
}
@Override
public int length() {
return charCount;
}
@Override
public String toString() {
return str(codePoints);
}
private static String str(int[] codePoints) {
// just for proof of concept
return new String(codePoints, 0, codePoints.length);
}
}
В итоге, нормальный код продолжит работать как раньше:
import java.io.PrintStream;
public final class NewStringDemo {
private static final String USER = "foror";
public static void main(String[] args) {
test(USER);
test(new Utf32String(USER));
}
private static void test(CharSequence cs) {
final PrintStream ps = System.out;
ps.println("Testing " + cs.getClass().getSimpleName() + ": " + cs);
final int charCount = cs.length() + 1;
for (int i = -1; i < charCount; i++) {
try {
ps.print(cs.charAt(i));
} catch (StringIndexOutOfBoundsException e) {
if (i >= charCount - 1) {
ps.println();
}
ps.println("\t// " + e.getMessage());
}
}
ps.println();
}
}
=>
Testing String: foror
// String index out of range: -1
foror
// String index out of range: 5
Testing Utf32String: foror
// String index out of range: -1
foror
// String index out of range: 5
Хотя по идее это должен быть какой-нибудь CharSequenceIndexOutOfBoundsException, ну да ладно.
В общем, StringIndexOutOfBoundsException — это API класса String, и если он выбросился, значит проблема в твоём коде (т.е. в коде, использующем класс String), а ArrayIndexOutOfBoundsException сигнализирует об ошибке в реализации класса String.
Действительно. Перепутал с String из Kotlin, в котором это поле. Коллизии возникают, когда в проекте одновременно Kotlin и Java, а IDE делает автодополнение. Извините.