Как избежать ошибки IndexOutOfBoundsException при итерации по JSON-массиву в Java
Что проверяют
Понимаете ли вы, откуда берётся IndexOutOfBoundsException и почему правильная защита от него это корректная итерация, а не try-catch. Следом обычно спрашивают, чем отличаются JSONArray из org.json, JsonArray из Gson и ArrayNode из Jackson при обращении к несуществующему индексу.
Как отвечать
Начните с причины: исключение появляется, когда индекс берётся не из самого массива. Типичные источники:
- условие
i <= size(): классическая ошибка на единицу, правильноi < size(); - чужая длина: цикл идёт по
ids.size(), а внутри читаетсяnames.get(i), и массивы в ответе разной длины; get(0)без проверки: код ждёт хотя бы один элемент, а API вернул[];- изменение массива в цикле: удаление элементов сдвигает индексы.
Лучшая защита: не работать с индексами вовсе. JsonArray в Gson и JsonNode в Jackson реализуют Iterable, поэтому подходит обычный for (JsonElement e : array). Ещё надёжнее отобразить JSON на DTO: objectMapper.readValue(json, new TypeReference<List<Item>>() {}) даёт типизированный List, а пустой массив превращается в пустой список.
Полезно знать поведение библиотек. В Gson JsonArray.get(i) за границей бросает IndexOutOfBoundsException. В org.json get(i) бросает JSONException, а opt(i) возвращает null. В Jackson get(i) возвращает null, а path(i) отдаёт MissingNode, с которым цепочка вызовов не падает.
И скажите, что индекс не единственная проблема: getAsJsonObject() бросит IllegalStateException, если элемент не объект, а get("name") вернёт null для отсутствующего поля, и следующий вызов закончится NullPointerException.
Где спотыкаются
Оборачивают цикл в try-catch с IndexOutOfBoundsException. Это исключение сигнализирует об ошибке в коде, его исправляют, а не ловят: такой обработчик прячет баг и оставляет данные обработанными наполовину.
Проверяют границы, но не структуру. Ответ API меняется, поле становится null или массив приходит вложенным, и падение просто переезжает в другое место.
Путают поведение библиотек и рассчитывают на исключение там, где Jackson молча вернёт null, а через десять строк случится NullPointerException.