Какие ошибки возникают при использовании substring с индексами и как их исправить?
Что проверяют
Знаете ли вы точный контракт substring и умеете ли защищать код от границ, а не просто ловить исключение. Следом нередко спрашивают, почему substring когда-то приводил к утечкам памяти.
Как отвечать
Начните с контракта. substring(begin, end) берёт символы с begin включительно по end не включительно, длина результата end - begin. StringIndexOutOfBoundsException (наследник IndexOutOfBoundsException) летит, если begin < 0, end > length() или begin > end. Граничный случай: "Hello".substring(5) возвращает пустую строку, а не ошибку.
Откуда берутся ошибки:
indexOfбез проверки: символа нет, приходит-1, иsubstring(-1)падает. ХужеindexOf(':') + 1: получается0, и код молча отдаёт всю строку;- off-by-one: забывают, что конец исключающий, и теряют последний символ;
- строка короче ожидаемой:
s.substring(0, 10)для превью падает на коротких строках. Исправление:s.substring(0, Math.min(10, s.length())); - суррогатные пары: индексы считаются в
char, а не в символах Unicode. Эмодзи занимает дваchar, разрез посередине даёт битую строку. Для таких случаев естьcodePointCountиoffsetByCodePoints; null: вызов наnullдаётNullPointerException, а не ошибку индекса.
Правильная защита это проверка входных данных до вызова, а не try-catch вокруг каждого substring. Если в проекте уже есть Apache Commons Lang, StringUtils.substring терпим к null и выходу за границы.
Про память: до Java 7u6 подстрока делила массив символов с исходной строкой, и короткий кусок удерживал в памяти огромный текст. Сейчас substring копирует данные, проблема историческая.
Где спотыкаются
Предлагают ловить StringIndexOutOfBoundsException как штатный сценарий. Исключение для управления потоком дорого и прячет реальную ошибку в логике.
Забывают, что строки неизменяемы: вызов s.substring(1) без присваивания ничего не меняет.
Не могут назвать точные условия исключения и путают, включается ли конечный индекс. Это обычно проверяют короткой задачкой прямо на собеседовании.